WEBVTT

00:00:00.000 --> 00:00:01.920
What if your database worked more like Git?

00:00:02.200 --> 00:00:09.340
Every change captured as an immutable event instead of a single mutating row that quietly forgets its own history.

00:00:09.860 --> 00:00:10.700
That's event sourcing.

00:00:10.820 --> 00:00:17.860
And Chris May is back on Talk Python, fresh off our Datastar panel, to walk us through what event sourcing actually looks like in Python.

00:00:18.360 --> 00:00:26.600
We'll cover core patterns, the libraries to reach for, when not to use it, and why event sourcing turns out to be a surprisingly good fit for AI-assisted coding.

00:00:27.180 --> 00:00:29.460
This is Talk Python To Me, episode 548.

00:00:29.460 --> 00:00:32.340
Recorded May 5th, 2026.

00:00:47.880 --> 00:00:54.600
Welcome to Talk Python To Me, the number one Python podcast for developers and data scientists.

00:00:54.880 --> 00:00:56.480
This is your host, Michael Kennedy.

00:00:56.840 --> 00:01:00.460
I'm a PSF fellow who's been coding for over 25 years.

00:01:01.020 --> 00:01:02.160
Let's connect on social media.

00:01:02.460 --> 00:01:05.640
You'll find me and Talk Python on Mastodon, Bluesky, and X.

00:01:05.820 --> 00:01:07.780
The social links are all in your show notes.

00:01:08.480 --> 00:01:12.040
You can find over 10 years of past episodes at talkpython.fm.

00:01:12.120 --> 00:01:15.540
And if you want to be part of the show, you can join our recording live streams.

00:01:15.700 --> 00:01:16.220
That's right.

00:01:16.420 --> 00:01:19.760
We live stream the raw, uncut version of each episode on YouTube.

00:01:20.240 --> 00:01:24.780
Just visit talkpython.fm/youtube to see the schedule of upcoming events.

00:01:24.920 --> 00:01:28.600
Be sure to subscribe there and press the bell so you'll get notified anytime we're recording.

00:01:29.200 --> 00:01:31.900
This episode is sponsored by Sentry's Seer.

00:01:32.200 --> 00:01:34.680
If you're tired of debugging in the dark, give Seer a try.

00:01:35.200 --> 00:01:40.500
There are plenty of AI tools that help you write code, but Sentry's Seer is built to help you fix it when it breaks.

00:01:40.980 --> 00:01:48.980
Visit talkpython.fm/sentry and use the code Talk Python26, all one word, no spaces, for $100 in Sentry credits.

00:01:49.460 --> 00:01:53.140
And it's brought to you by Temporal, durable workflows for Python.

00:01:53.140 --> 00:02:00.160
Write your workflows as normal Python code and Temporal ensures they run reliably, even across crashes and restarts.

00:02:00.420 --> 00:02:03.440
Get started at talkpython.fm/Temporal.

00:02:04.460 --> 00:02:05.120
Hey, Chris.

00:02:05.520 --> 00:02:05.840
Hey there.

00:02:05.840 --> 00:02:06.480
How's it going?

00:02:06.780 --> 00:02:07.300
I'm well.

00:02:07.380 --> 00:02:07.800
How are you?

00:02:08.100 --> 00:02:08.640
Oh, good.

00:02:08.780 --> 00:02:09.540
Good to hear it.

00:02:09.560 --> 00:02:11.600
I'm happy to have you back on the show.

00:02:11.920 --> 00:02:16.660
Last time we had you on the show, you were part of the panel around Datastar, and that was cool.

00:02:16.920 --> 00:02:21.820
Now we're going to talk about event sourcing, but we'll find a way to tie it back to Datastar just a bit, I think.

00:02:21.820 --> 00:02:22.960
I see it on the horizon.

00:02:23.340 --> 00:02:24.000
Or on the show notes.

00:02:25.080 --> 00:02:25.640
Sounds good.

00:02:25.640 --> 00:02:25.960
One of these.

00:02:26.260 --> 00:02:26.480
Yeah.

00:02:26.660 --> 00:02:28.460
Well, not everyone listens to every episode.

00:02:28.680 --> 00:02:32.020
We've got new listeners coming all the time, so give us the quick intro.

00:02:32.240 --> 00:02:32.860
Who are you, Chris?

00:02:33.120 --> 00:02:33.540
Who am I?

00:02:33.600 --> 00:02:33.940
Let's see.

00:02:34.060 --> 00:02:42.880
I am a Python developer for about 20 years and a long-time listener to the show, so it's a very big privilege to be on, finally, my own self.

00:02:43.640 --> 00:02:46.180
And by the way, great job continuing going, Michael.

00:02:46.260 --> 00:02:49.680
You're constantly putting out great content, so I really appreciate all your work.

00:02:50.480 --> 00:02:53.240
But as far as me, I learned the program as an adult.

00:02:53.960 --> 00:02:55.820
Friend suggested I learn Python.

00:02:56.240 --> 00:03:00.500
I hitched my wagon to this engine, and I've loved it ever since.

00:03:01.340 --> 00:03:04.620
I was a technical coach for a little while.

00:03:04.800 --> 00:03:08.680
I started the Python group here in Richmond, Virginia, PyRVA.

00:03:09.000 --> 00:03:10.580
So if you're local, come out.

00:03:10.940 --> 00:03:13.420
In fact, we're just two weeks away from the next meeting.

00:03:14.120 --> 00:03:14.240
Awesome.

00:03:14.340 --> 00:03:15.460
How frequently do you have meetings?

00:03:15.800 --> 00:03:16.580
Once a month now.

00:03:16.740 --> 00:03:20.480
In fact, if you look behind me, you can see all these blue dots are the meetings.

00:03:20.860 --> 00:03:21.860
Okay, excellent.

00:03:22.080 --> 00:03:22.420
Keep planning.

00:03:22.480 --> 00:03:23.900
What are some of the kind of topics you all have?

00:03:24.100 --> 00:03:24.520
Oh, man.

00:03:24.520 --> 00:03:29.160
We range pretty much whatever we can figure out that people are interested in.

00:03:29.160 --> 00:03:31.820
We've had a number of AI discussions.

00:03:32.040 --> 00:03:33.820
In fact, those have been really powerful.

00:03:34.000 --> 00:03:38.180
We've kind of lined up the chairs in a big circle and just have a discussion.

00:03:38.420 --> 00:03:40.060
And it's really incredible.

00:03:40.260 --> 00:03:47.140
You know, you have people on the whole spectrum of opinions about AI.

00:03:47.420 --> 00:03:49.560
So, yeah, it was very, very...

00:03:49.560 --> 00:03:50.840
That was one of my favorite...

00:03:50.840 --> 00:03:52.440
I was going to say episodes.

00:03:52.600 --> 00:03:53.560
One of my favorite meetings.

00:03:54.020 --> 00:03:59.960
I think we might bookend this podcast episode with a little AI at the start, a little AI at the end.

00:04:00.180 --> 00:04:00.680
Sounds good.

00:04:01.420 --> 00:04:01.620
Cool.

00:04:01.960 --> 00:04:03.520
So, yeah, people will just go attend that.

00:04:04.280 --> 00:04:06.920
And I guess probably a meetup.com is where they find you.

00:04:07.120 --> 00:04:07.820
It is, yeah.

00:04:08.020 --> 00:04:12.740
And you can go to pyrva.org to get to the meetup page either way.

00:04:12.840 --> 00:04:13.160
Yeah, easiest way.

00:04:13.320 --> 00:04:14.900
Because you can find a lot of crazy stuff.

00:04:14.980 --> 00:04:18.580
You'll probably find people with pet pythons that want to meet up in Virginia as well.

00:04:18.680 --> 00:04:19.520
And it's not the same thing.

00:04:20.040 --> 00:04:20.940
Indeed, yeah.

00:04:21.180 --> 00:04:24.340
Thankfully, and we are, gosh, over 10 years old.

00:04:24.340 --> 00:04:28.620
So we are one of the first ones to pop up just because of age, I think, sometimes.

00:04:28.940 --> 00:04:31.880
Although, honestly, some of the newer ones pop up ahead of us sometimes, too.

00:04:32.160 --> 00:04:32.680
So, you know.

00:04:32.880 --> 00:04:35.960
It's such a contentious topic, this AI stuff.

00:04:36.040 --> 00:04:37.080
You know, talking about your meetup.

00:04:37.320 --> 00:04:38.080
How did that go?

00:04:38.160 --> 00:04:39.000
Were people frustrated?

00:04:39.240 --> 00:04:39.820
People excited?

00:04:40.200 --> 00:04:42.460
Yeah, it was kind of the whole spectrum.

00:04:42.600 --> 00:04:45.280
You know, I felt like it was great because everybody respected each other.

00:04:45.420 --> 00:04:51.200
And there were, I'd say, two people anchored on each of the sides.

00:04:51.380 --> 00:05:01.860
You know, two people who, actually, maybe there were three people who, you know, have bought their own hardware and are really going deep into AI and, you know, encouraging people to, like, really dig into it.

00:05:01.980 --> 00:05:10.440
And we had two people who were very AI skeptic and very, you know, worried about the environment, you know, all sorts of different things.

00:05:10.760 --> 00:05:13.940
And so, I thought it was a very healthy, very good discussion.

00:05:14.580 --> 00:05:19.200
You know, I walked away with, you know, a healthier respect for both sides.

00:05:20.180 --> 00:05:28.640
Some ideas that I incorporated into my work, especially now that the company I work for gives us a mandate to use AI to write every piece of code.

00:05:28.760 --> 00:05:31.880
So, that's been a very fascinating transition for me.

00:05:32.420 --> 00:05:43.820
But it also gives me, you know, a little bit of agency or a little bit of permission to experiment and see what to do, you know, how to actually function in this new paradigm.

00:05:44.320 --> 00:05:44.940
It is engineering.

00:05:45.320 --> 00:05:50.260
And we'll talk about it more later, but it's quite wild that your company's, that is the position.

00:05:50.440 --> 00:05:52.700
I don't necessarily think it's the wrong position.

00:05:52.940 --> 00:06:02.840
I think it might be the right one, but it's, I think it's got to be brought on from a, from a, this is a skill you need to learn, not just throw stuff at the chat bot and now that's your job.

00:06:03.040 --> 00:06:04.680
Like, these are not the same things, you know?

00:06:04.760 --> 00:06:10.260
But I think a lot of people do, especially when they're getting started, treat them as the same thing and then say it doesn't work and then they're frustrated.

00:06:10.260 --> 00:06:11.100
Yeah, totally.

00:06:11.480 --> 00:06:11.660
Yeah.

00:06:11.940 --> 00:06:12.160
Yeah.

00:06:12.740 --> 00:06:13.100
Yeah.

00:06:13.420 --> 00:06:13.740
All right.

00:06:14.380 --> 00:06:15.200
More of that.

00:06:15.400 --> 00:06:18.520
We'll speak further about certain things, but yes, I agree.

00:06:19.220 --> 00:06:19.620
Absolutely.

00:06:19.820 --> 00:06:20.220
Absolutely.

00:06:20.400 --> 00:06:20.680
All right.

00:06:20.740 --> 00:06:27.640
Well, we'll, we'll come back to that and, and get there, but let's talk about a little bit of this event sourcing thing.

00:06:27.900 --> 00:06:28.220
Yeah.

00:06:28.520 --> 00:06:29.860
What exactly is event sourcing?

00:06:30.180 --> 00:06:30.640
That's a question.

00:06:30.720 --> 00:06:31.000
Okay, cool.

00:06:31.060 --> 00:06:32.200
I wasn't sure if you had more.

00:06:32.420 --> 00:06:32.980
I saw your.

00:06:33.080 --> 00:06:33.480
No, no.

00:06:33.540 --> 00:06:36.820
I think I, when you, when you reached out and said, Hey, let's talk about this.

00:06:36.940 --> 00:06:38.920
I'm like, I, so let's take a step back.

00:06:38.920 --> 00:06:39.320
Okay.

00:06:39.500 --> 00:06:43.820
Design patterns, refactoring ideas, like all of these architecture.

00:06:44.040 --> 00:06:45.500
I love to talk about this stuff.

00:06:45.560 --> 00:06:46.960
I love to think about this stuff.

00:06:47.020 --> 00:06:57.800
I think also, maybe that's a why, one of the reasons I'm not super frustrated with the AI things because I will tell it, I want you to use, like you could say like, I want to build a system with event sourcing and it's going to work this way.

00:06:57.800 --> 00:07:02.360
Like for me, the fun is like, Oh, I got to build some of the event source and it clicks together with this and it does that.

00:07:02.400 --> 00:07:07.280
And like, yeah, I didn't have to do all the little checks and details and like the file IO, but whatever.

00:07:07.400 --> 00:07:12.520
Like I can skip that and build just like, think a little bit bigger and a little more, more big building blocks.

00:07:12.820 --> 00:07:17.660
So I'm a big fan of design patterns and paying attention to what you're doing, I can tell that you are too.

00:07:18.000 --> 00:07:18.260
Yes.

00:07:19.700 --> 00:07:21.420
Especially event sourcing, I would say.

00:07:22.040 --> 00:07:27.180
So I have been following the topic of event sourcing for over a decade.

00:07:27.180 --> 00:07:36.100
I listened to a podcast in with a couple of developers in the PHP realm and they were talking about event sourcing and it just inspired me.

00:07:36.100 --> 00:07:39.140
specifically the things that I really loved.

00:07:39.480 --> 00:07:41.760
Before I was a programmer, I was a graphic designer.

00:07:42.160 --> 00:07:47.640
And so creating websites with exceptional user experiences is something that just makes me excited.

00:07:48.180 --> 00:08:01.760
And at the time, I was working at a creative agency building websites that would just slow, get slower and slower and slower, the more data we put into it or, you know, the more we configure the routing or the navigation and whatnot.

00:08:01.760 --> 00:08:08.480
And so the thought of never having a slow page load again was intoxicating to me.

00:08:08.980 --> 00:08:22.600
However, that was in a portion of my career where I was, had so much imposter syndrome, having learned to program in as an adult and I just felt like I couldn't suggest to my lead developer we should lean into this.

00:08:23.000 --> 00:08:32.100
And even when I was a lead developer, I just didn't feel confident that I could lead a whole team into like a redesign of the code.

00:08:32.720 --> 00:08:35.740
But a couple years ago, I got laid off and I was like, you know what?

00:08:35.820 --> 00:08:39.300
I've been wanting to explore event sourcing for 10 years.

00:08:39.540 --> 00:08:40.340
I'm going to do it.

00:08:40.660 --> 00:08:43.300
And it turns out it's a lot easier than I thought.

00:08:43.760 --> 00:08:47.460
But anyway, all this to say, let me define event sourcing since I've kind of danced around it.

00:08:47.720 --> 00:08:51.620
Event sourcing is how, has to do with how you save data to the database.

00:08:52.100 --> 00:08:56.760
The best way to contrast it is most apps are kind of CRUD based, right?

00:08:56.820 --> 00:09:00.540
So you create a table, like let's say you're a shopping cart application.

00:09:00.940 --> 00:09:10.200
You have a table called carts and you have a bunch of columns and one of the columns has data for the product IDs that are in the cart.

00:09:10.560 --> 00:09:19.940
And so if you have that kind of situation and you have one user who adds five items to the cart, then removes two and then checks out.

00:09:20.200 --> 00:09:23.680
And then you have another user who adds just three items to the cart and checks out.

00:09:23.880 --> 00:09:28.680
Well, if they check out at the same time and you look at the two database rows, they are very similar.

00:09:28.680 --> 00:09:30.480
They're the same user, basically.

00:09:30.720 --> 00:09:34.420
They get put in the same cohort from your marketing side, right?

00:09:34.680 --> 00:09:34.940
Yeah.

00:09:35.180 --> 00:09:38.560
Both of them checked out exactly the same products.

00:09:39.060 --> 00:09:44.600
And if you look at the database, you'd have no idea that one of them removed two items from their shopping cart.

00:09:44.840 --> 00:09:58.360
So event sourcing, so the reason that is because CRUD based applications will mutate state in the database to ensure it's always up to date with the current state and optimize for data integrity.

00:09:58.720 --> 00:10:03.960
Event sourcing, on the other hand, captures every change that happens within the system.

00:10:04.300 --> 00:10:10.000
So you would have an event of like cart created, item added to cart, item added to cart.

00:10:10.100 --> 00:10:13.760
You'd have five item added to cart events and two removals.

00:10:14.180 --> 00:10:19.640
And so you could have the whole history of how each user interacts with your system in the database.

00:10:19.780 --> 00:10:22.200
That is essentially the core of event sourcing.

00:10:22.200 --> 00:10:27.060
Everything else is actually adding more design patterns onto event sourcing, which is really wonderful.

00:10:27.220 --> 00:10:29.120
But that is what event sourcing is.

00:10:29.440 --> 00:10:29.520
Right.

00:10:29.620 --> 00:10:32.900
So your database sort of becomes almost an audit log.

00:10:33.080 --> 00:10:35.680
It feels very source control-ish.

00:10:35.880 --> 00:10:36.900
It feels like Git, right?

00:10:36.900 --> 00:10:40.740
Like what you store is the file and then the diff, then the diff, then the diff.

00:10:41.120 --> 00:10:45.120
You get back to the file by running all the operations on it, potentially.

00:10:45.500 --> 00:10:46.320
Yeah, exactly.

00:10:46.680 --> 00:10:47.880
Yeah, that's exactly what it is.

00:10:47.960 --> 00:10:52.460
And it's funny because like, I don't know about you, but like when I first heard about this, I'm like, well, isn't it slower?

00:10:52.600 --> 00:10:54.560
Because it just seems like you're doing so much more work.

00:10:54.620 --> 00:11:06.080
Every time you're updating the cart, you're pulling out all the events from the event store and building up the state of where it's at right now and saying, okay, you know, does that cart exist in the, does that item exist in the cart?

00:11:06.200 --> 00:11:06.900
Can I remove it?

00:11:07.100 --> 00:11:08.100
Okay, let's remove it.

00:11:08.240 --> 00:11:10.860
You know, and it turns out computers are fast.

00:11:12.540 --> 00:11:16.160
And so it's negligibly slower depending on the query.

00:11:17.000 --> 00:11:17.080
Yeah.

00:11:17.080 --> 00:11:21.960
So I saw you and Bob Belderbuss talking about this on YouTube and that was one of my first thoughts too.

00:11:22.040 --> 00:11:27.420
It was like, this is super cool, but it's kind of sounds a lot slower to answer questions.

00:11:27.720 --> 00:11:27.920
Yeah.

00:11:28.180 --> 00:11:35.980
And I think, but then I thought about it and I thought, I think there's actually a decent amount of stuff that you can do to make it quite a bit faster.

00:11:36.240 --> 00:11:36.620
Right.

00:11:36.680 --> 00:11:43.380
So let me throw some ideas out to you and then you tell me how they land as somebody who's actually done this stuff.

00:11:43.540 --> 00:11:46.260
First of all, back to your comment on computers are fast.

00:11:46.540 --> 00:11:47.420
Computers are so fast.

00:11:47.740 --> 00:11:51.680
They're so much faster than people realize how fast they are and databases are fast too.

00:11:51.760 --> 00:11:55.340
If you put indexes on them, then they're so much faster.

00:11:55.560 --> 00:11:57.680
I just don't understand how websites are slow.

00:11:58.060 --> 00:12:01.780
It's just, it's not just, oh, I'm a little frustrated.

00:12:01.880 --> 00:12:16.400
It's like, how is it possible that somebody built this and accepted that it takes three seconds to load this page and yet they do and you just know that it's most likely that there's not a database index somewhere or maybe on an extreme situation there should be better caching,

00:12:16.560 --> 00:12:17.820
but it's just like, ah.

00:12:18.180 --> 00:12:21.240
So like when done right, you're right, it's absolutely blazes, right?

00:12:21.480 --> 00:12:22.300
Yeah, absolutely.

00:12:22.900 --> 00:12:24.960
But how, you could make it faster.

00:12:25.040 --> 00:12:26.700
So a couple of thoughts that came to mind.

00:12:26.960 --> 00:12:28.940
One was, I have three.

00:12:29.120 --> 00:12:43.680
The one is you could have a operational database which has, for a particular user, it might have the five ads, two removals and that's their shopping cart and the way you get that is either you query it and then code you add it up or you do some kind of aggregation thing

00:12:43.680 --> 00:12:48.600
that says get all these things and then somehow plus minus them together, right?

00:12:48.820 --> 00:12:48.980
Yeah.

00:12:49.200 --> 00:12:53.300
Probably in the shopping cart it feels like you probably need to actually pull them back.

00:12:53.340 --> 00:13:04.400
But still, you could do that super quick and then just run that bit of code and every time you make a change you could also write that to a second table, second database that doesn't have the, it just has the current state.

00:13:04.620 --> 00:13:06.560
I just have three for that user shopping cart.

00:13:06.760 --> 00:13:10.320
That sounds okay to me but it's, I mean databases hate duplication.

00:13:10.320 --> 00:13:12.900
That's like kind of their third normal form job.

00:13:13.180 --> 00:13:17.060
Do databases hate duplication or is it people that don't like it?

00:13:18.140 --> 00:13:18.960
Yeah, that's fair.

00:13:19.040 --> 00:13:19.440
That's fair.

00:13:19.780 --> 00:13:21.720
I mean they were built to avoid duplication, right?

00:13:21.820 --> 00:13:22.480
So in that sense.

00:13:22.880 --> 00:13:27.380
So, but another, you know, another possibility would just be something like Valkey.

00:13:27.440 --> 00:13:30.800
You could, I could have said Redis but I'm a fan of Valkey over Redis.

00:13:31.040 --> 00:13:33.120
I find this is like a little bit nicer project.

00:13:33.800 --> 00:13:35.080
Are you familiar with Valkey?

00:13:35.340 --> 00:13:37.660
I am not and I'm taking notes mentally right now.

00:13:37.660 --> 00:13:38.380
Yeah, here we go.

00:13:38.940 --> 00:13:45.700
So Valkey, or if I find its repository which is hiding down here, it describes itself.

00:13:45.860 --> 00:13:46.820
Where does it describe itself?

00:13:47.220 --> 00:13:54.360
So a fork of the open source Redis project right before the transition to their new source available but not open source models.

00:13:54.720 --> 00:14:03.680
So if you have say the Redis Python library, you just tell it that it talks to this thing, this endpoint, this IP address and port and it thinks it's Redis, right?

00:14:03.700 --> 00:14:05.480
But it's like more open source friendly.

00:14:05.560 --> 00:14:06.420
I'm going to star it for the world.

00:14:06.680 --> 00:14:08.620
So, and it's got 26,000 stars, right?

00:14:08.680 --> 00:14:09.680
So it's pretty popular.

00:14:09.980 --> 00:14:20.040
Not that it's totally really relevant exactly which version this is but just having a cache that has that information of what is, you know, shopping cart is three, period.

00:14:20.280 --> 00:14:20.520
Yeah.

00:14:20.780 --> 00:14:23.220
And put something, just put two pieces in place.

00:14:23.340 --> 00:14:25.700
One, when you do a query, first you check the cache.

00:14:25.780 --> 00:14:30.300
If it's not there, you get the playback, you compute it and you put it in the cache.

00:14:30.460 --> 00:14:33.860
And if you make any change to that thing, then you invalidate the cache, right?

00:14:33.860 --> 00:14:41.820
Those two things would give you basically seamless ephemeral answers to the questions that if you ask them very often, you get super quick responses, right?

00:14:42.080 --> 00:14:42.420
Absolutely.

00:14:43.140 --> 00:14:43.320
Yeah.

00:14:43.400 --> 00:14:48.960
And then the other one is, if you, you know, I always find like these extra caching servers are honestly not necessary.

00:14:49.480 --> 00:14:50.820
You know, we already talked about FAST.

00:14:50.980 --> 00:14:57.440
So I'm a big fan of disk cache, which I had Vincent Warmerdom on to talk about and disk cache is awesome.

00:14:57.520 --> 00:15:02.360
So you could just have like a local file store on your Docker image or volume or whatever.

00:15:02.360 --> 00:15:05.660
Then you get the same thing, but you don't have to have the infrastructure, right?

00:15:05.720 --> 00:15:06.680
There's, there's different options.

00:15:06.800 --> 00:15:09.260
So basically, I guess to sum this up, I'll throw it to you now.

00:15:09.640 --> 00:15:14.640
Operational database that is also has the answers or some kind of caching story.

00:15:14.640 --> 00:15:17.560
It could be in memory, it could be a server like Valkeyrie.

00:15:17.700 --> 00:15:19.240
It could be the disk cache, whatever.

00:15:19.600 --> 00:15:20.460
What do you think about those?

00:15:20.740 --> 00:15:21.820
Are you guys all exploring them?

00:15:22.160 --> 00:15:26.780
I am exploring two, essentially, yeah, I guess you could say all three in a way.

00:15:27.100 --> 00:15:31.860
I'm, I'm experimenting with NATs to do kind of the, I guess, Redis kind of side of it.

00:15:31.860 --> 00:15:36.360
But all that to say is all three are viable options depending on your use case.

00:15:36.740 --> 00:15:39.560
The first thing is like just the event store itself.

00:15:39.900 --> 00:15:47.980
Like you, getting the current state of any individual item should not take, you know, essentially should take milliseconds if, if that long.

00:15:48.280 --> 00:15:54.720
One of the, so there are two people that I kind of, who are my North star for all of my event sourcing knowledge.

00:15:54.720 --> 00:15:57.940
they are Martin Dilger and Adam Dimitriuk.

00:15:57.940 --> 00:16:11.840
And Martin wrote a book called Understanding Event Sourcing, which was huge to helping me go from somebody who created an event sourcing project to adopting event sourcing as my kind of default strategy.

00:16:12.380 --> 00:16:26.840
And in, in the book, he mentioned that he will tend to use the event store for essentially, like, if you start hitting 2000 events in a stream, then he'll think about optimizing it, you know, changing, going to one of the alternate

00:16:26.840 --> 00:16:28.500
approaches that we just mentioned.

00:16:28.680 --> 00:16:30.180
So, like, that's really impressive.

00:16:30.420 --> 00:16:33.980
I, he uses Java or one of the Java derivative languages.

00:16:34.240 --> 00:16:36.820
So, chances are, it's slower in Python.

00:16:36.820 --> 00:16:40.900
And so you need, you know, that we need to adjust that number for Python.

00:16:41.020 --> 00:16:44.640
But honestly, we should have shorter event streams anyway.

00:16:44.940 --> 00:16:45.920
2000 seems like a lot.

00:16:46.100 --> 00:16:46.540
It does.

00:16:48.080 --> 00:16:48.980
Seems like a lot.

00:16:48.980 --> 00:16:54.240
This portion of Talk Python To Me is brought to you by Sentry and Seer AI.

00:16:54.820 --> 00:17:00.640
There are plenty of AI tools that help you write code, but Sentry Seer is built to help you fix it when it breaks.

00:17:01.080 --> 00:17:02.220
The difference is context.

00:17:02.820 --> 00:17:05.060
Seer isn't just guessing based on syntax.

00:17:05.320 --> 00:17:09.820
It's analyzing your actual Sentry data, your stack traces, logs, and failure patterns.

00:17:10.240 --> 00:17:20.060
Because it has the full context, it can, A, spot buggy code in review and help prevent issues before they happen, and B, identify the root cause of production errors.

00:17:20.900 --> 00:17:25.520
It can even draft a fix and hand the work off to an agent-like cursor to open a PR for you.

00:17:26.060 --> 00:17:28.160
Seer turns Sentry into a complete loop.

00:17:28.580 --> 00:17:33.240
You have your traces, errors, logs, and replays to see the problem and now AI to help solve it.

00:17:33.520 --> 00:17:39.500
Join millions of devs at companies like Claude, Disney+, and even Talk Python who use Sentry to move faster.

00:17:39.960 --> 00:17:48.760
Check them out at talkpython.fm/sentry and use code talkpython26, all one word, for $100 in Sentry credits.

00:17:49.220 --> 00:17:51.100
Thank you to Sentry for supporting Talk Python.

00:17:52.160 --> 00:18:05.940
Kind of the first fallback for me would be what Martin and Adam call the read model, which is essentially one way you can make a read model would be the database-backed read model where you have code that subscribes

00:18:05.940 --> 00:18:07.900
to only the events it cares about.

00:18:08.240 --> 00:18:14.240
And so whenever an event comes in, it'll incrementally update that database cache or your file cache or Redis cache or whatever.

00:18:14.240 --> 00:18:28.440
And then I guess the third thing that I appreciate is using Redis or in my case, Nats, is when you have a front-end, a very high-frequency, high-updating web UI or something

00:18:28.440 --> 00:18:36.620
that you want to really make sure that the user has up-to-date information, I would lean towards that having ways to push down to the client.

00:18:36.880 --> 00:18:39.620
Yeah, anytime you've got a live stream, it seems perfect, right?

00:18:39.840 --> 00:18:40.660
Yeah, absolutely.

00:18:40.660 --> 00:18:53.620
Yeah, I mean, hook up some JavaScript or hook in some textual or whatever it is you're trying to do and just say, or just write, you know, arbitrary web sockets or service and events and just say, when this changes, send me the Delta and then we'll adjust.

00:18:53.960 --> 00:18:54.140
Yeah.

00:18:54.180 --> 00:18:55.460
Which is pretty, pretty nice.

00:18:55.720 --> 00:18:55.900
Yeah.

00:18:55.980 --> 00:19:00.640
So there's a book that you recommended by one of the guys you mentioned, Martin Dilger.

00:19:00.960 --> 00:19:01.140
Yeah.

00:19:01.140 --> 00:19:02.180
Tell people about that real quick.

00:19:02.400 --> 00:19:05.640
Yeah, this is incredible to me.

00:19:05.760 --> 00:19:08.460
He realized he needs, there's a gap.

00:19:08.460 --> 00:19:22.400
One of the biggest problems with event sourcing is that the material is sometimes there's gaps in where there's good material and because event sourcing came out of the domain driven design community, there's a lot of jargon that you have to kind of get through.

00:19:22.980 --> 00:19:25.700
And they do like their jargon in the DDC space.

00:19:25.960 --> 00:19:26.920
They really do.

00:19:27.320 --> 00:19:29.560
And it, once you understand it, it makes perfect sense.

00:19:29.660 --> 00:19:30.320
But yeah, yeah.

00:19:30.340 --> 00:19:32.420
Getting onboarded does, does take.

00:19:32.500 --> 00:19:35.400
Gets your bounded context working and then off the races.

00:19:35.640 --> 00:19:36.400
Yeah, exactly.

00:19:36.400 --> 00:19:44.520
And so Martin essentially saw this gap in knowledge and was like, I need to fill this with an e-book.

00:19:44.620 --> 00:19:47.280
And I can't remember, I want to say in like two months he wrote this thing.

00:19:47.480 --> 00:19:52.840
And it's so amazing because it introduces the way that the two of them work.

00:19:52.960 --> 00:20:07.900
Like they both independently kind of came to similar conclusions, which is to use event sourcing as your base, but to also leverage two other or one main other, whatever, a couple of other patterns, vertical slice architecture, CQRS, which is kind of that idea

00:20:07.900 --> 00:20:14.800
of like having those read models ready to, you know, optimized for you to download and use.

00:20:14.940 --> 00:20:18.820
And then using a documentation technique called event modeling diagrams.

00:20:18.960 --> 00:20:33.080
And that, that is a huge key too because as someone who has been on a couple teams to do the event-driven transition to try to really help, you know, do more asynchronously, you need to have a good communication pattern

00:20:33.080 --> 00:20:35.580
to keep everybody up to date on what does what.

00:20:35.940 --> 00:20:48.860
And I find that all three, especially event modeling diagram, they have refined this to make it simpler and simpler and simpler to the point where there's really just a few elements put together and you can understand the whole life cycle of a, of an application.

00:20:49.240 --> 00:20:49.460
Yeah, cool.

00:20:49.520 --> 00:20:52.240
I'll link to the book on, over on Amazon.

00:20:52.480 --> 00:20:57.360
You know, another, before we carry on, I thought of another more optimized scenario.

00:20:57.680 --> 00:20:59.560
What about a document database like Mongo?

00:20:59.920 --> 00:21:00.160
Yeah.

00:21:00.160 --> 00:21:14.200
Your top level elements are just like the computed fields like total lifetime value or, you know, cart value or cart count, item count, but then have like maybe a cart item events, which could be a, a nested list

00:21:14.200 --> 00:21:24.140
of acts of like rich, you know, many documents that are like item added, item added, timestamp, value, like category, all, and actually storing them in the same record.

00:21:24.540 --> 00:21:24.680
Yeah.

00:21:24.920 --> 00:21:27.740
I haven't tried that, but I think it's a really interesting approach.

00:21:27.740 --> 00:21:33.560
You know, I actually use a document database as my fire store, as my, as my event store.

00:21:34.400 --> 00:21:38.640
And I haven't really kind of dug into like kind of the optimizations I could do.

00:21:38.880 --> 00:21:50.360
But I find it curious because like the, I mean, what you're suggesting is slightly different than how I think about it because it sounds like you have like a, like a better word, a model that you're storing all of its events in as well.

00:21:50.620 --> 00:21:55.680
And some of the neat, some of the, it's kind of inside out of what the real design pattern is, right?

00:21:55.680 --> 00:22:06.840
Well, it's not so much that as much as, one thing that I have found interesting is, you know, since this came out of the domain driven design group, everything is about an aggregate, what they call aggregate.

00:22:07.060 --> 00:22:08.120
Many people call it a model.

00:22:08.320 --> 00:22:14.840
And so you, you know, set up boundaries of this is your shopping cart and these are the events that modify the shopping cart.

00:22:15.020 --> 00:22:29.520
What has been a new movement in event sourcing is to, essentially be model less is to like focus on the events themselves because they are so flexible and so many times we as developers can kind of create

00:22:29.520 --> 00:22:35.000
boundaries around what we think are the models that, but the models change.

00:22:35.260 --> 00:22:35.540
Yeah.

00:22:35.840 --> 00:22:36.120
Yeah.

00:22:36.120 --> 00:22:38.800
And coupling is like the hardest thing.

00:22:38.800 --> 00:22:43.880
The bounded context, as I would say, actually changes because the problem you're solving might change and the models don't match.

00:22:44.140 --> 00:22:44.540
Exactly.

00:22:44.940 --> 00:22:45.180
Yeah.

00:22:45.440 --> 00:22:45.660
Yeah.

00:22:45.660 --> 00:22:50.320
So all that to say is I don't, not that I want to especially say like, I don't think that that's a bad idea.

00:22:50.320 --> 00:22:51.760
I think it could be really fascinating.

00:22:52.100 --> 00:23:05.980
especially as like a secondary approach because, you know, well, whatever, you know, like I, one of the things I really find fascinating about this is this is such a flexible pattern that people, I mean, they've done so many different ways of optimizing

00:23:05.980 --> 00:23:08.980
for their event store or anything like this.

00:23:08.980 --> 00:23:11.100
So I think that's a very much a valid approach.

00:23:11.420 --> 00:23:25.280
It's, it's, the reason it came to mind is you can atomically update documents and therefore you could atomically update both the computed value and the series of events as a single action, which is interesting, you know?

00:23:25.500 --> 00:23:26.500
Yeah, absolutely.

00:23:26.840 --> 00:23:27.380
Very interesting.

00:23:27.440 --> 00:23:30.860
And they kind of, that, that one thing becomes the source of truth for what you're tracking.

00:23:30.960 --> 00:23:32.420
I don't, there might be something there.

00:23:32.520 --> 00:23:35.540
I don't, but it does sound a little bit too focused on the model.

00:23:35.640 --> 00:23:36.220
I do think.

00:23:36.420 --> 00:23:37.760
It's worth experimenting with for sure.

00:23:38.120 --> 00:23:47.660
So just, to throw out a little street cred there, look at this, purchased April 18th, 20, 2005, the domain driven design by Eric Evans.

00:23:47.740 --> 00:23:50.240
So this is kind of the greater space, right?

00:23:50.320 --> 00:23:54.680
Maybe the book is called domain driven design, tackling the complexity in the heart of software.

00:23:54.840 --> 00:23:55.640
It's pretty interesting.

00:23:55.940 --> 00:24:05.000
I think it's kind of the follow-on of the refactoring movement that Martin Fowler and all those folks were working on, like in the late 90s, early 2000s.

00:24:05.200 --> 00:24:05.420
Yeah.

00:24:05.460 --> 00:24:06.320
Kind of in that space, right?

00:24:06.620 --> 00:24:06.880
Yeah.

00:24:07.220 --> 00:24:08.700
I must say, I haven't bought that book.

00:24:08.700 --> 00:24:19.660
The closest I've come is the Cosmic Python book or the architecture patterns in Python book that Harvey and, oh, I always forget the other guy's name, but that's such an amazing book.

00:24:19.740 --> 00:24:21.240
So that's the closest I've come to DDD.

00:24:21.600 --> 00:24:24.000
There's a video.

00:24:24.140 --> 00:24:25.680
I think, I think you gave me this video, right?

00:24:25.780 --> 00:24:27.040
Events, we're seeing explain football.

00:24:27.480 --> 00:24:27.660
Yeah.

00:24:27.660 --> 00:24:31.580
And this looks like foosball type football, not American football.

00:24:31.980 --> 00:24:32.200
Indeed.

00:24:32.440 --> 00:24:35.880
I love American football, but I do believe it's slightly misnamed.

00:24:36.160 --> 00:24:38.340
Like, you don't use your feet that much, other than the red card.

00:24:38.680 --> 00:24:38.820
Yeah.

00:24:40.820 --> 00:24:41.520
True that.

00:24:41.840 --> 00:24:49.200
I mean, it's like calling Formula One, like, foot car, because you make the car go with your foot, but it's not really the main thing of the sport anyway.

00:24:49.460 --> 00:24:49.680
Yeah.

00:24:50.480 --> 00:24:51.480
But yeah, I love this video.

00:24:51.860 --> 00:24:52.020
Yeah.

00:24:52.140 --> 00:24:52.280
Okay.

00:24:52.360 --> 00:24:53.120
Tell me about it.

00:24:53.160 --> 00:24:53.740
I'll put it in the show notes.

00:24:54.040 --> 00:24:54.200
Yeah.

00:24:54.260 --> 00:25:00.900
This is, you know, I feel like event sourcing, it's like one of those things where it's hard to explain until you get it.

00:25:00.920 --> 00:25:02.620
And then I feel like it's like a good board game.

00:25:02.880 --> 00:25:06.640
You know, if you have a board game fan in your life, they're like, oh, this is such a great board game.

00:25:06.680 --> 00:25:07.380
It's so simple.

00:25:07.560 --> 00:25:11.540
And then they start explaining it and like half an hour later, you're like, are we ever going to actually play this?

00:25:11.580 --> 00:25:12.600
I don't know that I want to anymore.

00:25:12.920 --> 00:25:18.940
But I felt like the, this person has done a really good job of kind of really distilling it down and showing like why it matters.

00:25:19.440 --> 00:25:22.360
And it's a 10 minute video, you know, five minutes at 2X.

00:25:22.520 --> 00:25:24.300
And it's, it's really kind of charming.

00:25:24.520 --> 00:25:24.900
Really good.

00:25:25.120 --> 00:25:25.500
Really well done.

00:25:25.580 --> 00:25:25.780
Okay, cool.

00:25:25.860 --> 00:25:26.120
Yeah, yeah.

00:25:26.120 --> 00:25:26.660
I'll put it on there.

00:25:26.800 --> 00:25:27.960
Can you watch videos at 2X?

00:25:28.340 --> 00:25:29.180
Oh yeah, all the time.

00:25:29.420 --> 00:25:29.600
Yeah.

00:25:29.840 --> 00:25:30.600
My daughter does that.

00:25:30.640 --> 00:25:33.120
I'm like, how do you actually take it in?

00:25:33.160 --> 00:25:34.700
I just, I'm a 1X sort of person.

00:25:34.880 --> 00:25:38.780
I do slow it down or rewind to, to pull in things, but yeah.

00:25:38.780 --> 00:25:39.000
Let's see.

00:25:39.100 --> 00:25:42.000
It's like a, like a seek and then focus sort of deal.

00:25:42.120 --> 00:25:42.480
Exactly.

00:25:42.820 --> 00:25:43.200
Exactly.

00:25:43.500 --> 00:25:44.480
Not that one.

00:25:44.480 --> 00:25:45.280
This one.

00:25:45.580 --> 00:25:47.780
I also heard there's this ebook I can get.

00:25:47.860 --> 00:25:48.440
What's up with this?

00:25:48.780 --> 00:25:49.080
Yeah.

00:25:49.320 --> 00:25:55.100
So scheduling this podcast episode, I didn't know, you know, what we're going to talk about.

00:25:55.160 --> 00:25:57.080
And I know like, there's going to be things I forget.

00:25:57.380 --> 00:26:08.580
And I feel like part of the reason I am so excited about this is I know that there's someone like me, the 10 year ago version of me who has heard about these things and is curious, but just needs more information.

00:26:08.980 --> 00:26:18.280
And so I've spent the last couple of weeks creating this ebook and I put the first version up and I'm going to continue to improve it as time goes on.

00:26:18.420 --> 00:26:25.200
So if anything in this conversation is interesting to you and you just need a little bit more and you want to understand a little bit more what's going on, absolutely download it.

00:26:25.400 --> 00:26:26.580
And, you know, it's free.

00:26:26.820 --> 00:26:27.260
So why not?

00:26:27.540 --> 00:26:27.660
Cool.

00:26:27.820 --> 00:26:32.780
And then we'll have to make you do a, an audio version, put that on audible or something like that.

00:26:32.960 --> 00:26:33.540
Sounds good.

00:26:33.820 --> 00:26:34.360
Yeah, sure.

00:26:34.620 --> 00:26:42.380
I always want to do audio books for stuff that I'm working on, but just the concept of trying to speak code or config file, I just like, I got to stop.

00:26:42.580 --> 00:26:43.540
You know, it's, it's tough.

00:26:43.600 --> 00:26:47.340
It's a tough balance to do with audio books and tech, like developer stuff, but still.

00:26:47.600 --> 00:26:48.140
For sure.

00:26:48.500 --> 00:26:48.700
Yeah.

00:26:48.760 --> 00:26:48.980
Cool.

00:26:49.040 --> 00:26:49.220
All right.

00:26:49.220 --> 00:26:50.100
So people can check that out.

00:26:50.120 --> 00:26:50.620
It's for free.

00:26:50.740 --> 00:26:51.960
We'll put that in the show notes.

00:26:51.960 --> 00:27:01.560
Now, I think that this both has really positive or really big possibilities for data science, but also potential challenges.

00:27:02.040 --> 00:27:03.980
Let me throw it out to you and then you, you take us through it.

00:27:04.200 --> 00:27:06.540
Super benefits, incredibly obvious.

00:27:06.540 --> 00:27:10.900
You have an event stream that tells you over time what times the things happened.

00:27:11.020 --> 00:27:17.800
You have, both the additions and subtractions or the permutations that it goes through until it ends up in its final state.

00:27:17.800 --> 00:27:26.660
Not just show me all the customers from California who bought this month, but like show me all the Californians who abandoned the cart, but then came back and then did the, you know what I mean?

00:27:26.660 --> 00:27:29.020
Like you can just answer way more interesting questions.

00:27:29.020 --> 00:27:30.300
You got time series.

00:27:30.460 --> 00:27:38.180
On the other hand, maybe I would just want to load up a pandas data frame with the answers of what's the average cart size during checkout.

00:27:38.360 --> 00:27:43.620
And that, that becomes like a big computation out of an event source based database.

00:27:44.080 --> 00:27:44.800
If you don't have one of things.

00:27:45.020 --> 00:27:45.420
Okay.

00:27:45.480 --> 00:27:46.720
Well, let's hear it.

00:27:46.840 --> 00:27:47.240
Let's hear it.

00:27:47.240 --> 00:27:47.680
I'm going to say it.

00:27:47.680 --> 00:27:56.000
Like if you, if you don't do one of those caching or multi-database things or the QRS, I don't remember the patterns.

00:27:56.100 --> 00:27:58.640
Anyway, that looks like it maybe is a little bit of a challenge.

00:27:59.020 --> 00:27:59.700
You could do it.

00:27:59.760 --> 00:28:09.000
I think you could do it more easily in pandas, but like maybe I just, you know, some people do data science just through SQL and they just, I'm just going to write queries against a warehouse database, you know?

00:28:09.000 --> 00:28:09.920
Yeah, absolutely.

00:28:10.120 --> 00:28:11.000
Why not have it both ways?

00:28:11.660 --> 00:28:21.540
For example, on my, okay, so let's start the, for the hardcore data scientist, actually, you know, I don't even think the event store is the right format for them.

00:28:21.740 --> 00:28:34.720
You know, I would definitely have some kind of script that would run on some kind of loop that, you know, maybe every day or every couple hours or whatever would transform the raw events into some format that would be great for.

00:28:34.880 --> 00:28:35.080
Sure.

00:28:35.120 --> 00:28:40.340
And you hear about all these like OLAP cubes and all these other like super BI type of systems.

00:28:40.840 --> 00:28:42.800
None of those, no, no, I can't say none of those.

00:28:42.860 --> 00:28:45.720
Many of those are not running out of the operational database.

00:28:45.820 --> 00:28:49.000
They're like a, some kind of like warehouse data lake.

00:28:49.100 --> 00:28:50.860
We've transformed this so you answer questions.

00:28:51.000 --> 00:28:52.700
So it's not necessarily just event sourcing.

00:28:52.940 --> 00:28:56.860
Like we just want to avoid five joins so we can just ask the question directly, right?

00:28:57.080 --> 00:28:57.260
Yeah.

00:28:57.540 --> 00:28:57.720
Yeah.

00:28:57.780 --> 00:29:07.260
And in fact, my current project that I have in production at work, it is a service that multiple other services use to process items.

00:29:07.500 --> 00:29:19.080
And the project manager of one of these services reached out to me and said that they have a BigQuery table that has all this analytical information and they wanted to add the information we have to theirs.

00:29:19.460 --> 00:29:22.000
And so, you know, we set up a conversation.

00:29:22.280 --> 00:29:26.380
I created the code and every day I'm sending information to their BigQuery instance.

00:29:26.860 --> 00:29:33.760
And three days after we did a go live, you know, I created a meeting to like kind of circle back with them to make sure everything's working the way they wanted.

00:29:34.220 --> 00:29:40.400
And when they opened up the BigQuery database, they were shocked because they were expecting three days worth of data.

00:29:40.760 --> 00:29:48.160
I had, I set every piece of data I had for months, which was how long they've been sending things to my service.

00:29:48.520 --> 00:29:58.720
And so, like, I was just, I just, you know, this person was elated because they were like, they knew their data scientists wanted this information and they, now they have all this information going back to day one, so to speak.

00:29:59.480 --> 00:30:07.380
And also just recently, my boss asked me, like, I have a reports view that's just a webpage that has like how, stats on how my service is doing.

00:30:07.660 --> 00:30:12.460
And he's like, it'd be nice to have like, some, like a table of some of these, you know, last few days or whatever.

00:30:12.620 --> 00:30:15.040
And I was like, okay, how many, how many days would you like?

00:30:15.080 --> 00:30:16.000
And he's like, 30 days.

00:30:16.120 --> 00:30:24.900
So I created, the HTML was pretty easy and I just created a script to like pull the events out of the event store and populate this table, you know, as exactly as we needed.

00:30:25.060 --> 00:30:28.260
It went into production live and we were immediately there with 30 days of history.

00:30:28.260 --> 00:30:29.880
It was, it was so exciting.

00:30:29.880 --> 00:30:38.640
And, and like, this is what I get to experience every week is like, you know, having the ability to like, go back into history and answer questions that we've had that we didn't even think we knew.

00:30:38.900 --> 00:30:42.200
We didn't have any idea that we would want to know, you know, a month ago.

00:30:42.260 --> 00:30:45.700
And to be able to answer those questions with precision is, is intoxicating.

00:30:46.080 --> 00:30:46.200
Yeah.

00:30:46.460 --> 00:30:47.420
I certainly see the value.

00:30:47.500 --> 00:30:50.900
Like you don't necessarily know the questions you're going to ask.

00:30:50.920 --> 00:30:56.240
And if you don't have enough data or you don't store it in the right way, you literally can't answer them.

00:30:56.380 --> 00:30:56.560
Yeah.

00:30:56.760 --> 00:30:56.960
Right.

00:30:57.200 --> 00:31:02.160
But with, it sounds like with, events or so, you can go back and like, well, what if we ask this over time instead of by region?

00:31:02.320 --> 00:31:04.180
Like, okay, slightly different query, no problem.

00:31:04.500 --> 00:31:04.780
Exactly.

00:31:05.160 --> 00:31:05.340
Yeah.

00:31:05.600 --> 00:31:05.800
Yeah.

00:31:05.960 --> 00:31:07.580
It's, it's really quite something.

00:31:07.700 --> 00:31:09.180
I had no idea.

00:31:09.360 --> 00:31:15.060
Like my, I kind of mentioned earlier, my biggest thing was, I was, I can't wait to have fast UI.

00:31:15.200 --> 00:31:29.320
And now that I realized that I feel like our applications obviously serve the primary purpose of whatever it is that the business needs, but I didn't realize how much there was a secondary need of understanding how it works and enabling the business to make decisions

00:31:29.320 --> 00:31:31.980
based on how customers are actually using the application.

00:31:32.340 --> 00:31:38.680
We're going to talk about the AI side later, but I do just want to throw out as different constituents who might care to answer these questions.

00:31:38.840 --> 00:31:46.260
Like I was just thinking, you've got, you've got the operational side of say the website or app or, you know, driving an API for the app or something like that.

00:31:46.380 --> 00:31:47.240
That's one view.

00:31:47.320 --> 00:32:00.880
That's kind of the traditional view, but now you have this much more increasingly popular view of like data scientists and BI tools and the CEO wants a dashboard that updates live type, you know, so events are a clear trigger for those kinds of things, right?

00:32:01.140 --> 00:32:01.500
Absolutely.

00:32:01.840 --> 00:32:11.560
But then also you might ask your AI Opus or Codex or whatever, hey, find me some trends or let's look at this and, you know, it has more to work with as well, right?

00:32:11.800 --> 00:32:12.000
Yeah.

00:32:12.160 --> 00:32:13.920
Just thinking of the different constituencies, yeah?

00:32:14.200 --> 00:32:14.500
Totally.

00:32:14.880 --> 00:32:23.640
In fact, just today I was looking into a bug that was happening in production and I asked Claude, hey, can you query the GCP logs?

00:32:23.740 --> 00:32:26.460
Can you query the event store and help me understand what's going on?

00:32:26.480 --> 00:32:30.340
And it was like, sure enough, here you go and made fixing the bug much easier.

00:32:32.920 --> 00:32:35.660
This portion of Talk Python is sponsored by Temporal.

00:32:36.020 --> 00:32:42.520
Ever since I had Mason Egger on the podcast for episode 515, I've been fascinated with durable workflows in Python.

00:32:43.040 --> 00:32:47.700
That's why I'm thrilled that Temporal has decided to become a podcast sponsor since that episode.

00:32:48.140 --> 00:32:56.280
If you've built background jobs or multi-step workflows, you know how messy things get with retries, timeouts, partial failures, and keeping state consistent.

00:32:56.900 --> 00:33:03.460
I'm sure many of you have written brutal code to keep the workflow moving and to track when you run into problems, but it's trickier than that.

00:33:03.640 --> 00:33:08.640
What if you have a long-running workflow and you need to redeploy the app or restart the server while it's running?

00:33:09.220 --> 00:33:12.560
This is where Temporal's open-source framework is a game-changer.

00:33:13.240 --> 00:33:27.480
You write workflows as normal Python code and Temporal ensures that they execute reliably, even across crashes, restarts, or long-running processes while handling retries, states, and orchestrations for you so you don't have to build and maintain that logic yourself.

00:33:27.700 --> 00:33:33.420
You may be familiar with writing asynchronous code using the async and await keywords in Python.

00:33:33.920 --> 00:33:42.160
Temporal's brilliant programming model leverages the exact same programming model that you are familiar with but uses it for durability, not just concurrency.

00:33:42.160 --> 00:33:47.040
Imagine writing awaitworkflow.sleep Heimdelta 30 days.

00:33:47.380 --> 00:33:49.320
Yes, seriously, sleep for 30 days.

00:33:49.460 --> 00:33:51.380
Restart the server, deploy new versions of the app.

00:33:51.620 --> 00:33:52.040
That's it.

00:33:52.220 --> 00:33:53.380
Temporal takes care of the rest.

00:33:53.920 --> 00:33:58.420
Temporal is used by teams at Netflix, Snap, and NVIDIA for critical production systems.

00:33:58.920 --> 00:34:01.620
Get started with the open-source Python SDK today.

00:34:01.940 --> 00:34:04.360
Learn more at talkpython.fm/Temporal.

00:34:04.660 --> 00:34:06.680
The link is in your podcast player's show notes.

00:34:07.080 --> 00:34:09.100
Thank you to Temporal for supporting the show.

00:34:09.840 --> 00:34:11.220
Yeah, I guess you know why.

00:34:11.360 --> 00:34:26.080
You have more granularity on what, if the thing in the database doesn't look like you expected, you much, have a much more granular way of knowing like it was this step that made it look like that because I've had problems before where I completely

00:34:26.080 --> 00:34:31.700
upgraded, swapped out the data access layer for Talk Python training for the courses.

00:34:32.100 --> 00:34:32.200
Yeah.

00:34:32.200 --> 00:34:33.600
And for the website, it was perfect.

00:34:33.820 --> 00:34:34.600
Everything was great.

00:34:34.660 --> 00:34:43.820
But under certain circumstances on Android, the app was resulting in something, it was sending in something that would make the data not right, right?

00:34:43.840 --> 00:34:47.300
Like there was some field that was null instead of just taking on the default value.

00:34:47.540 --> 00:34:48.100
Oh, man.

00:34:48.360 --> 00:34:49.000
Which is fine.

00:34:49.060 --> 00:34:57.180
But then when the person logged in on the website, the website didn't assume that that thing could be null because it was, at a minimum, had a non-nullable default value.

00:34:57.280 --> 00:34:59.060
I'm like, why do we need to check this for null?

00:34:59.060 --> 00:35:01.040
How did it get to be null?

00:35:01.100 --> 00:35:01.880
It makes no sense.

00:35:01.960 --> 00:35:03.620
It took forever to figure that out.

00:35:04.020 --> 00:35:04.340
Oh, wow.

00:35:04.480 --> 00:35:08.540
But with event sourcing, you could see this was the event that made it null.

00:35:08.660 --> 00:35:09.700
Not just, it is null.

00:35:09.800 --> 00:35:11.100
What in the world is going on?

00:35:11.180 --> 00:35:12.980
Why could it, how could it possibly be null?

00:35:13.380 --> 00:35:14.320
Yeah, absolutely.

00:35:14.800 --> 00:35:17.460
So I think it's got some interesting debugging.

00:35:17.960 --> 00:35:32.940
And one more thing, like I know this is quite the data science side, but another constituency could be PCI, HIPAA, GDPR, like all the compliance frameworks you got to deal with for auditing or sort of audit trail

00:35:32.940 --> 00:35:33.600
or something that happens.

00:35:33.700 --> 00:35:37.840
I mean, a lot of times logs serve that value, but that might be a, they updated the record like, oh, what?

00:35:38.560 --> 00:35:39.320
Yeah, totally.

00:35:39.620 --> 00:35:39.900
Yeah.

00:35:40.220 --> 00:35:51.620
And that, you know, I, even though I've been in insurance and I've been in healthcare, I haven't had anything where I have to certify these things, but like you've, the audit log is the way you interact with everything.

00:35:51.620 --> 00:35:53.600
It is the source of truth.

00:35:53.600 --> 00:36:00.960
And so, but what's funny is I have worked on teams that created history tables to try to essentially do that work.

00:36:00.960 --> 00:36:06.680
and it was like two or three months after I started working there before I learned that that table existed.

00:36:06.840 --> 00:36:12.640
And so, there were two or three months of work I should have been putting in the history table that I didn't.

00:36:12.900 --> 00:36:17.000
And from what I hear among other developers, a lot of teams work that way.

00:36:17.060 --> 00:36:21.600
Like, only a few people really know and understand how to maintain that history table.

00:36:22.000 --> 00:36:25.080
And a lot of times, like when they try to replay it, it just doesn't work.

00:36:25.160 --> 00:36:26.180
And it's, it's unfortunate.

00:36:26.180 --> 00:36:30.040
Yeah, it's like, well, there is history in the history table.

00:36:30.360 --> 00:36:34.040
When we run it again, we don't get the same output as the final database.

00:36:34.160 --> 00:36:34.700
What's going on?

00:36:34.920 --> 00:36:35.700
Yeah, true.

00:36:36.020 --> 00:36:38.360
Yeah, but with the event sourcing, it reverses it.

00:36:38.420 --> 00:36:44.500
Basically, the events are the source of truth and the other one is some kind of dynamically generated sort of deal, yeah?

00:36:44.740 --> 00:36:45.480
Yeah, yeah.

00:36:45.600 --> 00:36:48.840
And it's a lot like, you know, a backup strategy.

00:36:49.100 --> 00:36:51.700
You know, if you never test your backup strategy, you don't really.

00:36:52.260 --> 00:36:52.700
Exactly.

00:36:52.960 --> 00:36:54.580
And I feel like it's the same thing with the history table.

00:36:54.660 --> 00:37:01.660
And honestly, to be totally honest, event sourcing is similar in that it's easy to accidentally migrate event versions.

00:37:01.980 --> 00:37:16.220
You know, like for myself, I was working on a new event to kind of, you know, on my app and I introduced a new attribute or actually, I guess it was a full, whatever the point being is, at some point I decided I wanted to change

00:37:16.220 --> 00:37:24.480
the name of the attribute because it would reflect better what it meant in the domain and not realizing that I had already published that event to production.

00:37:24.480 --> 00:37:39.440
And so at one point I was, I don't know, I don't remember what I was doing, looking up issues or honestly, it might have been a view that it was rendering that was supposed to be for with throwing errors and I couldn't understand why and I looked at it and sure enough, it was because I accidentally created a different version

00:37:39.440 --> 00:37:40.180
of the same event.

00:37:40.500 --> 00:37:47.200
Thankfully, all I had to do was change the code to say, well, if this attribute doesn't exist, look for this attribute and everything was fixed.

00:37:47.340 --> 00:37:51.800
But, you know, you can honestly fall into some of those things with event sourcing too if you're not careful.

00:37:51.800 --> 00:37:56.600
But the nice thing is because the events are still there, you have the ability to recover from them.

00:37:56.860 --> 00:37:58.420
Let's talk about versioning for a little bit.

00:37:58.680 --> 00:37:59.080
Sure.

00:37:59.380 --> 00:38:04.760
On a sort of operational third normal form type of database, you know, you might run a migration.

00:38:04.960 --> 00:38:11.600
One of the reasons I really like using MongoDBs because I almost never have to run migrations, but that's a different, it's a different debate.

00:38:11.860 --> 00:38:22.740
However, you might run the migration to say like, okay, we're going to add a column or we're going to split this data apart and move this stuff over here and that over there and then create a foreign key relationship or whatever.

00:38:23.060 --> 00:38:23.280
Yeah.

00:38:23.520 --> 00:38:26.320
But I can see if you've got this kind of history of things.

00:38:26.320 --> 00:38:29.400
Like, let's say, I don't know, how do you deal with versioning, right?

00:38:29.440 --> 00:38:34.100
Like, I've got these old events and the way you're not storing the current state.

00:38:34.180 --> 00:38:38.760
So with the migration or something like that, you're like, well, let's just transform the current state into the new state.

00:38:38.880 --> 00:38:44.940
With these, you've got like old events and new events and they might be in a real way incompatible.

00:38:45.220 --> 00:38:45.420
Yeah.

00:38:45.680 --> 00:38:46.120
Yeah, sure.

00:38:46.420 --> 00:38:47.560
What do you think about with that?

00:38:47.840 --> 00:38:49.380
You have so many strategies.

00:38:50.200 --> 00:38:52.340
You just have to choose which one works for your situation.

00:38:52.860 --> 00:39:07.760
So the first one is kind of what I mentioned just a minute ago, kind of like the MongoDB or I should say document database way of working with things where if you're adding things to an event, adding fields, then if, you know, if the code, you know, most code will be blissfully ignorant

00:39:07.760 --> 00:39:09.640
that you're adding new attributes to it.

00:39:09.720 --> 00:39:10.980
So it doesn't really matter.

00:39:11.320 --> 00:39:14.400
And then those that do care can kind of have fallbacks.

00:39:14.400 --> 00:39:25.100
And the way that Adam and Martin suggest, you essentially have like upcasters or some kind of code that essentially says like, okay, the previous version, actually, that's two different things.

00:39:25.180 --> 00:39:25.480
I'm sorry.

00:39:25.760 --> 00:39:32.300
The code that does care about the new attribute, if it encounters an older event that doesn't have that attribute, then you can have a default fallback.

00:39:32.560 --> 00:39:37.120
And it's best to have those close to, you know, the domain logic that you want to update.

00:39:37.220 --> 00:39:41.540
This is a vertical slice architecture approach as opposed to having like a global upcaster.

00:39:41.940 --> 00:39:46.760
Again, I realized that I want to keep going to the upcasting, which is the second option that I've been trying to get to.

00:39:47.220 --> 00:39:50.100
But so essentially one is, you know, have a default fallback.

00:39:50.340 --> 00:40:01.720
Second one is to have an upcaster that says, okay, you know, especially if they're two different versions, like truly different versions of the event, you know, you have add to shopping or item added and item added version two.

00:40:02.060 --> 00:40:03.620
You know, you might have completely different fields.

00:40:03.620 --> 00:40:08.180
It's good to have a piece of code that can, you know, upcast to the second one.

00:40:08.780 --> 00:40:11.000
You put that in your, like your data access layer.

00:40:11.000 --> 00:40:19.660
It might write a thing and say, give me all the items of the cart and it looks at the type or the version flag and then does a little processing or would you rewrite the database?

00:40:20.140 --> 00:40:21.800
Oh, well, that's, I was going to say that's your third option.

00:40:22.440 --> 00:40:30.920
So let me take a step back and ask your first, your last question, which was like, at least to me, the tent, what you're doing with your events is essentially rebuilding state.

00:40:30.920 --> 00:40:37.940
And so wherever you're in that loop to rebuild the state, you would probably say like, oh, is it this event or is it this event or whatever behave this way?

00:40:37.960 --> 00:40:38.140
Right there.

00:40:38.140 --> 00:40:44.060
Like in my story of using one of the data caches, you do a request, it's not in the cache.

00:40:44.120 --> 00:40:46.240
So you've got to run your build it up code and put it in the cache.

00:40:46.340 --> 00:40:55.760
And that just, I mean, that part right there would be the part that goes, okay, we're going to transform it differently now and then we'll still store the answer in the cache and the next time they ask, it's just fast.

00:40:55.760 --> 00:40:56.200
Yeah.

00:40:56.940 --> 00:41:02.480
So yeah, you would have, the way I would code it is you'd have a piece of code that's listening into the events.

00:41:02.600 --> 00:41:06.140
So you have, it knows about the old version of the event and the new version of the event.

00:41:06.260 --> 00:41:12.880
And it knows what format that data needs to be in in that Redis cache or whatever it was that you suggested.

00:41:13.180 --> 00:41:13.640
Yeah, Valkey.

00:41:13.760 --> 00:41:14.240
Come on, Valkey.

00:41:14.260 --> 00:41:14.500
Valkey.

00:41:14.560 --> 00:41:15.300
Let's go, Valkey.

00:41:15.300 --> 00:41:16.960
I'm going to remember this by the end of the conversation.

00:41:18.620 --> 00:41:27.980
So yeah, so what it does is it will be able to say like, okay, this event is an old one, but I can upcast it to a new one and convert it into the format or however we need to save it to Valkey.

00:41:28.240 --> 00:41:32.480
And then if it's a new one, it also knows, okay, I'm going to convert it this way to save to Valkey.

00:41:33.040 --> 00:41:39.320
So it's nice that it's kind of localized to, you know, the process that you need to update, upcast.

00:41:39.800 --> 00:41:45.860
And then we've touched on like kind of the quote unquote nuclear option, which is to apply a transform to your entire event store.

00:41:46.180 --> 00:41:50.180
And so you would, by doing that, you would create a new database from your database table, which would be your new event store.

00:41:50.320 --> 00:41:58.280
And you, for each event, you just copy it over, do some kind of map or transform to upcast the entire, your entire history.

00:41:58.920 --> 00:41:59.280
Yeah.

00:41:59.520 --> 00:42:01.220
I see values, value in all of them.

00:42:01.280 --> 00:42:05.860
You know, if you're doing a lot of direct SQL data science-y stuff, you probably want to transform the database.

00:42:06.160 --> 00:42:12.240
If it's primarily coming out of an API, like just let that thing handle it as it reads them, you know, computers are fast.

00:42:12.420 --> 00:42:12.940
Keep it in mind.

00:42:13.160 --> 00:42:13.420
Indeed.

00:42:13.560 --> 00:42:16.600
And I forgot to mention that, oh, his name escapes me right now.

00:42:16.640 --> 00:42:22.720
The guy who popularized event sourcing back in the 2000s wrote a book on this topic specifically.

00:42:22.720 --> 00:42:27.400
So he kind of listed out all of your strategies and when you would want to choose them and why.

00:42:27.860 --> 00:42:28.920
Are we talking Martin Dilger?

00:42:29.320 --> 00:42:29.660
No.

00:42:30.680 --> 00:42:31.340
Greg Young.

00:42:31.580 --> 00:42:31.960
Greg Young.

00:42:32.080 --> 00:42:32.260
Okay.

00:42:32.480 --> 00:42:33.840
I think it's on LeanPub.

00:42:34.140 --> 00:42:35.120
Yeah, that sounds about right.

00:42:35.220 --> 00:42:39.500
In fact, Martin Dilger's book is cheaper on LeanPub as well and you get additional content there too.

00:42:39.860 --> 00:42:40.000
Okay.

00:42:40.400 --> 00:42:41.380
Yeah, very interesting.

00:42:42.280 --> 00:42:45.700
Let's, let's make this a little bit concrete for people.

00:42:46.020 --> 00:42:46.260
Sure.

00:42:46.520 --> 00:42:55.440
We talked about how you might, in theory, architect some software, could be Python or something else to follow these patterns, but there is a Python library, right?

00:42:55.440 --> 00:42:56.480
Yeah, absolutely.

00:42:56.820 --> 00:42:57.600
Do you recommend it?

00:42:57.840 --> 00:42:58.160
I do.

00:42:58.380 --> 00:43:03.840
You know, I, it's funny, I don't have any production code with it, but I have used it a lot over the years.

00:43:04.460 --> 00:43:11.780
John Bywater has done an incredible job maintaining this, this repo and, you know, all his, all the people who have contributed as well.

00:43:12.040 --> 00:43:17.780
He has shepherded this through and is, has been really making it such an incredible application.

00:43:18.580 --> 00:43:25.900
When I wrote my applications, you know, I, the first one I did, I was like, I want to do it myself so I can understand it.

00:43:26.140 --> 00:43:28.720
And so I can really understand and respect what he's done.

00:43:29.520 --> 00:43:35.700
But also, you know, there's a part of me that really, like a lot of the, you know, essentially I feel like it depends on who you are.

00:43:35.700 --> 00:43:40.720
If you're somebody who wants to grab a framework and run with it, this is an exceptional one to do it with.

00:43:40.840 --> 00:43:50.800
It, essentially, you just write Python classes and you decorate them or subclass from some of his classes and all the magic of event sourcing happens for you.

00:43:50.860 --> 00:43:54.200
And it just make, leaves you with really readable, understandable code.

00:43:54.300 --> 00:44:00.360
And then you'll have other people who, you know, a lot of people in the event sourcing space says it's actually not that complicated.

00:44:00.840 --> 00:44:02.560
You can write your own code to do it.

00:44:02.900 --> 00:44:03.800
And I did.

00:44:03.920 --> 00:44:06.120
And I recommend it for the right type of person.

00:44:06.120 --> 00:44:09.780
For me, it was hard because there's so many decisions that you need to make.

00:44:09.800 --> 00:44:11.520
And I am not the best Python programmer.

00:44:11.680 --> 00:44:15.340
I do not know all the concurrency issues and all these things.

00:44:15.340 --> 00:44:16.580
I'm getting to learn them more.

00:44:17.080 --> 00:44:20.860
But, you know, I have software that's running in production that's, that's doing well.

00:44:20.940 --> 00:44:25.440
So all that to say is, yeah, I highly recommend this package, especially if you're new to it.

00:44:25.580 --> 00:44:30.200
It can really show you, you know, how you, one option of, of things can work.

00:44:30.200 --> 00:44:42.020
And I love that it, by default, it uses, well, you can, you can use SQLite, Postgres, or one of the, a couple of the doc, databases that are optimized for event sourcing.

00:44:42.020 --> 00:44:48.760
And so you can kind of see how it's, you know, some of the many ways you can pattern things to make it easy for you.

00:44:48.760 --> 00:44:49.160
Interesting.

00:44:49.420 --> 00:44:52.600
So I probably need to file a PR or something here.

00:44:52.800 --> 00:44:55.960
It says, the way you get it is pip install event sourcing.

00:44:56.060 --> 00:44:57.980
I feel like it should be pip install event sourcing.

00:44:58.680 --> 00:44:59.500
No, just kidding.

00:44:59.580 --> 00:45:00.120
But that's cool.

00:45:00.420 --> 00:45:06.820
However, I am, you know, so it's, you know, you can get it off PyPI, but I'm having a hard time resisting pressing this.

00:45:07.180 --> 00:45:08.080
Ask DeepWiki.

00:45:08.480 --> 00:45:09.840
Have you ever gone, what is DeepWiki?

00:45:10.240 --> 00:45:10.640
Yeah.

00:45:11.000 --> 00:45:15.860
It's a AI powered document thing that he opted into, which I thought was very fascinating.

00:45:16.140 --> 00:45:19.540
I, I was following, I was at the time he did it.

00:45:19.540 --> 00:45:20.980
I was, I think I was writing my own code.

00:45:21.060 --> 00:45:22.300
And so I had Slack open.

00:45:22.380 --> 00:45:30.260
He has a good Slack channel and was like showing all the things that he was able to, to all the insights that was able to be gleaned from it.

00:45:30.400 --> 00:45:31.040
This is epic.

00:45:31.160 --> 00:45:31.600
I love it.

00:45:31.840 --> 00:45:37.380
So it had, the DeepWiki apparently is like, and knows the source and the docs.

00:45:37.480 --> 00:45:38.640
And then it's just a chat.

00:45:38.820 --> 00:45:41.860
And even on fast, I asked, I said, give me an example of using this library.

00:45:41.960 --> 00:45:42.280
So sure.

00:45:42.300 --> 00:45:48.560
Here's a complete example of dog school application, all the code using event source, the light, the package.

00:45:48.760 --> 00:45:50.140
This is nuts.

00:45:50.480 --> 00:45:50.660
Yeah.

00:45:51.940 --> 00:45:52.900
Side quest unlocked.

00:45:53.120 --> 00:45:55.700
Must figure out how to get my packages into DeepWiki.

00:45:55.940 --> 00:45:56.580
This is nice.

00:45:57.080 --> 00:46:05.180
And I also want to add, he has other companion packages that for example, connect into Django and I believe Flask and some other ones too.

00:46:05.180 --> 00:46:19.280
So one of my side projects, I'm leveraging this with Django and it's really cool because one of the things that enables you to do is configure your events table to be similar to your,

00:46:19.320 --> 00:46:24.340
I guess in the same database as your Django table or at least configurable from the way Django would do it.

00:46:24.740 --> 00:46:28.440
And yeah, so getting all these read models are very easy with all the migrations.

00:46:28.440 --> 00:46:34.300
You just say, this is what I want my data to look like with Django and of course apply migrations and there it is in production.

00:46:34.520 --> 00:46:35.160
So that's really nice.

00:46:35.180 --> 00:46:35.860
Yeah, cool.

00:46:36.060 --> 00:46:37.920
It also has extension projects.

00:46:38.400 --> 00:46:39.120
What are these?

00:46:39.400 --> 00:46:43.160
The Django one, the CurrentDB, K-U-R-R-E-N-T.

00:46:43.300 --> 00:46:45.640
I imagine CurrentDB is probably a...

00:46:45.640 --> 00:46:50.680
I believe that is, yeah, it's one of the first event sourcing specific databases.

00:46:51.140 --> 00:46:51.960
I think it was called...

00:46:51.960 --> 00:46:54.780
Oh, it's for intelligent and responsive systems.

00:46:55.320 --> 00:46:57.160
I don't know, Chris, I just got to rant a little bit.

00:46:57.240 --> 00:47:05.920
Like there's all these projects that are cool and they do neat stuff and now I feel when I go to them that it's like, this is the AI compute data frame or this is the AI, the intelligent AI.

00:47:06.060 --> 00:47:10.500
It's like, it's just a database or just a data frame that AIs can use.

00:47:10.560 --> 00:47:14.740
That doesn't make it an AI data frame, you know, it's like, but they all want to capture the excitement.

00:47:14.880 --> 00:47:15.600
It drives me crazy.

00:47:15.980 --> 00:47:16.200
Yeah.

00:47:16.500 --> 00:47:18.880
And what's worse is when they don't even say exactly what they do.

00:47:18.880 --> 00:47:22.640
It is, it is your answer for AI-ing the thing that we're not going to tell you.

00:47:22.740 --> 00:47:23.300
I hate it.

00:47:23.420 --> 00:47:23.580
Yeah.

00:47:24.300 --> 00:47:24.880
Yeah, exactly.

00:47:24.960 --> 00:47:27.780
And it just obscures what the heck it is, but it's the H1 and the H2.

00:47:27.880 --> 00:47:28.780
You're like, oh my gosh.

00:47:29.020 --> 00:47:29.280
Yeah.

00:47:29.780 --> 00:47:30.140
Yeah.

00:47:30.200 --> 00:47:30.420
Okay.

00:47:30.480 --> 00:47:32.140
But that does look pretty interesting.

00:47:32.360 --> 00:47:39.980
Like, yeah, look, it's example is create a client, new event data, new UUID, et cetera, order place, serialize.

00:47:39.980 --> 00:47:48.700
So right here, this example is basically it's got primary key, a category or type of event, like a, just an event, I guess is the way you would call it.

00:47:48.800 --> 00:47:53.380
But then it has JSON serialized, like a JSON blob.

00:47:53.580 --> 00:47:55.120
That is the details of the event.

00:47:55.200 --> 00:47:56.600
Is this how you typically do it?

00:47:56.920 --> 00:47:57.760
I would say so.

00:47:57.760 --> 00:48:01.280
Or is it more column oriented where like this one has an order ID and a total.

00:48:01.380 --> 00:48:05.760
So you might have an order ID and a total in the data structure or is it in a blob level?

00:48:06.100 --> 00:48:06.300
Yeah.

00:48:06.440 --> 00:48:16.880
The implementations I've seen generally will have some kind of blob or JSON serialized or bytecode serialized optimization of it.

00:48:17.000 --> 00:48:22.060
You know, because each event, you know, when you're saving things to the database, you know, you're going to save an event.

00:48:22.140 --> 00:48:23.340
It's going to have an event stream.

00:48:23.340 --> 00:48:26.060
It's going to have generally speaking, there's probably an event version.

00:48:26.520 --> 00:48:29.780
Like there's all these specific things, but the actual payload of the event.

00:48:29.780 --> 00:48:32.960
If there's not an event version, you're going to wish there was an event version at some point probably.

00:48:33.360 --> 00:48:33.760
Exactly.

00:48:34.100 --> 00:48:34.380
Yes.

00:48:34.700 --> 00:48:39.200
And so the payload is usually some kind of blob or JSON body or something like that.

00:48:39.340 --> 00:48:41.440
It sounds very good to be a document database.

00:48:41.860 --> 00:48:42.180
Indeed.

00:48:42.580 --> 00:48:42.800
Yeah.

00:48:43.040 --> 00:48:43.300
Yeah.

00:48:43.400 --> 00:48:50.480
Because you can put indexes on like the sub items and then if they're not in that event, it just doesn't use the index for those particular ones.

00:48:50.480 --> 00:48:51.760
I mean, it's a lot of things.

00:48:52.080 --> 00:48:52.180
Yeah.

00:48:52.520 --> 00:48:53.100
Yeah, exactly.

00:48:53.200 --> 00:48:53.740
It's pretty sweet.

00:48:54.000 --> 00:48:54.160
Yeah.

00:48:54.300 --> 00:49:06.860
And again, well, I haven't said it quite, but like one of the things I have been thinking about for a decade is the more I kind of thought about it, the event sourcing and the patterns and unlocks really gives you so much flexibility.

00:49:07.380 --> 00:49:13.220
You know, you can use document data stores and like really take those, the power of that.

00:49:13.400 --> 00:49:19.480
You know, if you have, and part of this is too is just data, you know, vertical slicing or whatever, it's both multiple patterns put together.

00:49:19.580 --> 00:49:28.680
But like, you know, if you have a view that would be so much better served by having a graph query, a graph database, then use it.

00:49:28.800 --> 00:49:39.220
You know, it's, I remember at one time it took me a while, but like somebody told me that they were using, I can't remember their, their open query.

00:49:39.380 --> 00:49:40.040
Is that what it's called?

00:49:40.160 --> 00:49:47.340
The, I forgot the old name of what I'm trying to think of, but essentially it's, you know, like a database that optimizes for saving text.

00:49:47.340 --> 00:49:48.860
So you can like search for it.

00:49:49.300 --> 00:49:55.440
You know, they use that as just for one, you know, to serve the purpose of one item.

00:49:55.740 --> 00:49:57.540
And honestly, this isn't unique to event sourcing.

00:49:57.620 --> 00:50:00.120
You can do this with event-driven architecture as well.

00:50:00.380 --> 00:50:08.360
But what I love about event sourcing is like you have the benefits of event-driven architecture and the benefits of a monolith in one if you choose to go that way.

00:50:08.840 --> 00:50:16.060
And yeah, it's just, it's, I guess really what it comes down to is what I love about it and was surprised by is how flexible it gives you the ability.

00:50:16.500 --> 00:50:27.680
Yeah, in the book, it reminds me, one of my users was complaining about the status screen that I show for the users and he had all these great ideas and I was like, you know what?

00:50:27.880 --> 00:50:29.300
I want to take advantage of that.

00:50:29.420 --> 00:50:39.460
So I actually cloned my, the vertical slice for that view and created a new database column or collection for that, to power that view.

00:50:39.460 --> 00:50:54.020
and we iterated and iterated to make this thing better and with each iteration, sometimes I needed to change how the read model reacted to events and so I could just blow away the read model, regenerate it from events and we ended up with something really great so that when it

00:50:54.020 --> 00:51:03.300
was time to go live, I just changed which, where the URL went, pointed to the new one and was able to delete the old code and delete the database table and it was wonderful.

00:51:03.720 --> 00:51:08.180
Yeah, it just gives you so much flexibility to do whatever you need.

00:51:08.900 --> 00:51:14.480
So, a couple more, one more, I guess one more really relevant thing, two more things to give a shout out with this event sourcing.

00:51:14.580 --> 00:51:18.000
There's event sourcing Django which is Python package for it with Django.

00:51:18.320 --> 00:51:20.680
Imagine that probably somehow it upgrades with the ORM, don't know.

00:51:20.900 --> 00:51:23.280
But also event sourcing SQLAlchemy which is kind of cool.

00:51:23.540 --> 00:51:25.480
So if you use SQLAlchemy, yeah, very nice.

00:51:25.760 --> 00:51:36.680
All right, so this stuff is great but I imagine that it has times you should use it maybe more and times you should go, well, square peg round hole maybe not this time.

00:51:36.860 --> 00:51:37.700
Sure, yeah.

00:51:37.760 --> 00:51:38.100
What do you think?

00:51:38.260 --> 00:51:45.000
For me, I feel like it's usually the way I think about it first is because most people are very comfortable with not using event sourcing, right?

00:51:45.160 --> 00:51:47.860
And so I usually answer it the opposite way which is when should you?

00:51:48.040 --> 00:51:48.700
Sure, exactly.

00:51:49.080 --> 00:52:03.600
The two biggest, the best piece of advice that I heard over the last decade was number one, use it, a good opportunity to use it is if you have a database column called status because if you have a columnated status then that means that

00:52:03.600 --> 00:52:07.040
one item can be in multiple different statuses, right?

00:52:07.080 --> 00:52:19.980
Different states and if you're having different states each states behave different in some way or form and so you are definitely not dealing with true CRUD create, read, update, delete patterns and so event sourcing would be a great option for that.

00:52:20.200 --> 00:52:24.960
The second piece of advice is do you ever, are you ever concerned about losing data?

00:52:25.200 --> 00:52:30.500
Because by default event sourcing does not and what it enables you to do is choose when to lose data, right?

00:52:30.500 --> 00:52:32.380
Because you don't have to keep every event around forever.

00:52:32.800 --> 00:52:37.400
You can just say like after 90 days let's just put it to cold storage or just delete it, you know, it depends.

00:52:37.580 --> 00:52:37.880
Yeah, exactly.

00:52:38.040 --> 00:52:42.320
Out in the audience Mike says, I'm scared of the physical storage requirements of this potentially.

00:52:42.700 --> 00:52:47.500
I guess it depends how many data, how many events make up a final state in your system.

00:52:47.740 --> 00:52:49.620
Like a cart checkout, big deal?

00:52:49.800 --> 00:52:50.540
No, probably not.

00:52:50.860 --> 00:52:53.840
Like if used as an app log, that might be a problem.

00:52:54.100 --> 00:52:54.720
Yeah, yeah.

00:52:54.820 --> 00:53:02.660
Most, I'll say models, will have maybe a dozen events, maybe two, depends on your, obviously depends on your domain.

00:53:03.180 --> 00:53:12.640
But ideally, you will keep your events short and they have practices called closing the books where you will use events in your domain to kind of keep it short.

00:53:12.740 --> 00:53:25.580
So like, for example, a store will want to know their revenue across the entire year, but every night they shut down, they get their cash registers or if they still have cash registers and they kind of reconcile how much money they made that day.

00:53:25.880 --> 00:53:28.860
And so, you know, kind of keeping your event stream short really helps.

00:53:29.080 --> 00:53:37.440
If you're going to go back, you would just say, well, we'll just read the daily summary and then add today's events or something like to get the final output, something like that.

00:53:37.680 --> 00:53:37.900
Yeah.

00:53:38.040 --> 00:53:46.000
Unless you want to go all the way back to day one, in which case you can, you know, read and say like, okay, the, you know, it all depends on how you want to do it, right?

00:53:46.060 --> 00:53:57.060
This is again, the flexibility side of it because you could just like, say, start from today and read forward or you can start from today and say, okay, what was the event stream before this and read that and keep going back to the originating?

00:53:57.320 --> 00:54:02.680
And I think you put up Mike's comment that said, I'm afraid of the physical storage requirements.

00:54:02.820 --> 00:54:04.480
And it's like, that is the trade-off.

00:54:04.580 --> 00:54:14.440
There is, it will take more space, but thankfully, storage space is the cheapest commodity in all of online or, you know, in today's world.

00:54:15.200 --> 00:54:20.800
And it's, and most expensive is memory and then compute and then storage and then bandwidth and then storage.

00:54:20.900 --> 00:54:22.760
I think that's probably the breakdown, right?

00:54:22.960 --> 00:54:23.880
Yeah, I think so.

00:54:24.200 --> 00:54:29.580
And why things like disc cache are awesome versus like another thing that's just in a memory cache, but another process, right?

00:54:29.680 --> 00:54:30.440
Like, exactly.

00:54:30.840 --> 00:54:31.060
Yeah.

00:54:31.300 --> 00:54:45.040
And having the ability to say like, you know, we, you know, like my current application, I have not yet deleted any events, but truly like the only reason we have events older than even a week are just for analytical purposes and, and just me understanding how our system works.

00:54:45.040 --> 00:54:49.700
And so I'm planning to make a way to offload that event or those events.

00:54:49.860 --> 00:54:57.780
And a lot of people just put them straight to cold storage, you know, just so that they always have a backup just in case, but, you know, chances are they rarely ever use it.

00:54:57.960 --> 00:54:58.160
Interesting.

00:54:58.600 --> 00:55:02.840
And one other thing I did want to add is to go answer your question when not to use event sourcing.

00:55:02.980 --> 00:55:03.280
exactly.

00:55:03.700 --> 00:55:07.880
Would be essentially like, you know, so let's say you don't care about losing data.

00:55:08.360 --> 00:55:12.360
There are just a number of just simple applications that are truly crud, right?

00:55:12.420 --> 00:55:15.420
Like I've worked on a number of these where they're just forms over data.

00:55:16.080 --> 00:55:18.540
It's exactly the term I was thinking, forms over data.

00:55:18.780 --> 00:55:20.060
Defining that for people if they don't know.

00:55:20.280 --> 00:55:30.540
Yeah, it's essentially something where like in my case, one of the first ones I worked on is like you have a web page that almost exactly mirrors the database table that you're saving the data to.

00:55:30.800 --> 00:55:31.940
You know, maybe it's a contact form.

00:55:32.360 --> 00:55:33.620
Who knows what it could be?

00:55:33.760 --> 00:55:41.180
You know, the idea is like there is so the web UI or whatever you're building is just an easy way to get data into the database.

00:55:41.180 --> 00:55:44.200
And chances are you don't have status field.

00:55:44.340 --> 00:55:49.200
You don't have all these different ways of different rules for how things behave.

00:55:49.400 --> 00:55:53.960
And in fact, in my event source application, I have a model that is not event sourced.

00:55:54.200 --> 00:55:56.000
It is truly a crud model.

00:55:56.180 --> 00:56:00.560
And so just by saying, you know, adopting event sourcing doesn't mean you have to do it for everything.

00:56:00.680 --> 00:56:05.660
You can use it for even just a small bit of your project, especially if you want to try it out and see how it could be.

00:56:05.660 --> 00:56:06.260
That's a really good point.

00:56:06.400 --> 00:56:07.940
It's not an all or nothing sort of thing.

00:56:07.940 --> 00:56:14.980
Because you have a properly factored data access layer and you're not doing that inside of your Jinja template, are you?

00:56:15.220 --> 00:56:15.320
No?

00:56:16.180 --> 00:56:16.580
Right.

00:56:17.940 --> 00:56:22.660
Not even in your view, but like you've got just an opaque layer of actions.

00:56:22.820 --> 00:56:25.040
Some of those actions can be driven by events.

00:56:25.420 --> 00:56:27.340
Some of those actions can just be straight crud.

00:56:27.540 --> 00:56:29.220
Create, read, update, delete for those who don't know.

00:56:29.440 --> 00:56:42.040
One of the people who inspired me to really dig into event sourcing, he has a line of business that, well, he'll go to a company who is struggling because their database schema is holding them back.

00:56:42.360 --> 00:56:49.940
You know, for whatever decision they made, they cannot, they're having such a hard problem, hard time creating a new feature because of their database schema.

00:56:50.200 --> 00:57:01.020
So he goes in, teaches them event sourcing and uses the event sourcing event store to publish both the dream schema that they wish they would have and the old schema.

00:57:01.400 --> 00:57:15.280
And they live side by side and the event, you know, once the features are complete, they'll, you know, put it up and they'll start slowly migrating traffic over to the new event source version and, you know, eventually they can delete the old database table or schema, you know, database.

00:57:15.700 --> 00:57:21.280
And most of the teams he's worked with have kept with the event source version and gone on from there.

00:57:21.560 --> 00:57:21.720
Yeah.

00:57:21.860 --> 00:57:30.240
Oh, and then finally, one other thing I want to mention too is when not to use is it's up to your teammates because, you know, I am sold.

00:57:30.380 --> 00:57:33.020
I think this is such an incredible pattern.

00:57:33.140 --> 00:57:41.680
It is just unlocking so much joy again and so much flexibility as I've said before that I cannot imagine having to go back.

00:57:41.860 --> 00:57:47.560
That said, if I join a new team and my team members are like, I don't know, I'm going to go with them, you know.

00:57:48.120 --> 00:57:48.480
Yeah.

00:57:49.480 --> 00:57:51.700
One thing is to not use an optimal pattern.

00:57:52.020 --> 00:58:01.860
What's worse is to try to use an optimal pattern but have nobody else want to do it and then they work around it and you, you know, it sounds a little similar to like people who don't want to do unit testing.

00:58:02.200 --> 00:58:02.360
Yeah.

00:58:02.360 --> 00:58:11.580
So some of the people write the unit test and they set up CICD that'll fail if the unit test failed but then the other people will check and work without running the test at all and then they break it and you're like, what are you doing?

00:58:11.780 --> 00:58:13.360
Like, well, I don't want to run these crappy tests.

00:58:13.480 --> 00:58:16.260
You're like, well, now the whole CICD is not just not helpful.

00:58:16.440 --> 00:58:19.380
It's inhibiting me working because you won't even, you know what I mean?

00:58:19.380 --> 00:58:23.700
It's just like, and it seems like you do need a certain level of buy-in for this to make sense.

00:58:24.040 --> 00:58:24.360
Absolutely.

00:58:24.860 --> 00:58:25.060
Yeah.

00:58:25.360 --> 00:58:28.660
And maybe they should listen to this podcast and they can see it.

00:58:28.660 --> 00:58:36.180
And maybe you create an example of one feature in an event sourced way so they can see some of the benefits.

00:58:36.480 --> 00:58:36.820
But, you know.

00:58:37.040 --> 00:58:37.680
Yeah, yeah, yeah.

00:58:37.680 --> 00:58:39.220
Like your partial example, indeed.

00:58:39.480 --> 00:58:39.720
Yeah.

00:58:39.980 --> 00:58:40.260
All right.

00:58:40.640 --> 00:58:45.640
We're getting short on time here, Chris, but let's talk this AI flow.

00:58:45.640 --> 00:58:52.020
First of all, let's circle back to your comment of your company having a mandate to use AI.

00:58:52.440 --> 00:58:54.000
What the heck is going on here?

00:58:54.380 --> 00:58:56.680
How is this received and how are you receiving it?

00:58:56.900 --> 00:59:03.720
And also tell us, are you actually writing, you know, make, shipping more features and be more productive or not?

00:59:03.940 --> 00:59:06.620
Like what, give us your assessment as much as you're willing to share.

00:59:06.700 --> 00:59:07.500
Like you don't have to like.

00:59:08.820 --> 00:59:09.440
Yeah, yeah.

00:59:09.440 --> 00:59:13.560
I will, I will hide certain things, but to say.

00:59:13.560 --> 00:59:16.260
Names and places have been changed to protect the parties.

00:59:16.260 --> 00:59:19.300
Yes, and emotions and conversations with multiple other people.

00:59:20.160 --> 00:59:23.840
I would say at times I am so much more productive.

00:59:23.840 --> 00:59:30.240
At times it has brought down the production, you know.

00:59:30.500 --> 00:59:32.820
So it is a mixed case.

00:59:33.400 --> 00:59:39.000
I see that Mike in the chat said it's an overconfident intern and I'm like 110%.

00:59:39.000 --> 00:59:40.500
Like this is exactly what it is.

00:59:40.500 --> 00:59:41.040
But very smart intern.

00:59:41.360 --> 00:59:41.660
It is.

00:59:41.720 --> 00:59:42.220
Oh, absolutely.

00:59:42.380 --> 00:59:43.060
Very confident.

00:59:43.260 --> 00:59:43.840
Oh, well, he said that.

00:59:43.880 --> 00:59:44.420
Yeah, overconfident.

00:59:44.800 --> 00:59:58.620
And I find this fascinating because my production app is actually three services in one monorepo and I'm responsible for one and, you know, a couple other people are responsible for the other ones, but, you know, we're all interacting.

00:59:59.100 --> 01:00:07.960
And so my, when I need to change something on my code, you know, and I'm required to use cloud code, I say this is what I need to do and generally it does a really great job.

01:00:08.040 --> 01:00:15.600
And I think a lot of this has to do with the vertical slice architecture because vertical slices only hold code that is responsible for one feature.

01:00:15.960 --> 01:00:18.780
And so that really fits very nice into a context window.

01:00:18.780 --> 01:00:19.180
Yeah.

01:00:19.380 --> 01:00:22.900
It doesn't have to scan 200,000 lines and 100 files.

01:00:23.060 --> 01:00:24.000
It looks at five.

01:00:24.260 --> 01:00:24.520
Yeah.

01:00:24.820 --> 01:00:26.160
And it knows event sourcing.

01:00:26.300 --> 01:00:28.560
So it knows, okay, I'm subscribing to events.

01:00:28.700 --> 01:00:29.360
These are the events.

01:00:29.440 --> 01:00:31.480
I know where they are, you know, all these different things.

01:00:31.780 --> 01:00:38.360
When I work on one of the other services, it takes a lot more context to understand the state of the code.

01:00:38.540 --> 01:00:45.920
And I really have to work harder to do, to do what I need to do in those, in those parts of the code base.

01:00:46.240 --> 01:00:46.360
Yeah.

01:00:46.600 --> 01:00:48.360
So it's been a very interesting experiment.

01:00:48.500 --> 01:00:56.000
And additionally, kind of when I am, I had to curb this, but when I have been more productive is creating get work trees.

01:00:56.320 --> 01:00:59.440
So it's like, I have a kind of main repo that I work out of.

01:00:59.480 --> 01:01:04.920
And then I, if I have a feature that I, you know, I'm like looking at the code base and like, oh, or the web app or the logs.

01:01:04.920 --> 01:01:06.960
And I'm like, oh, it'd be good to like optimize this.

01:01:07.060 --> 01:01:11.580
Then I create a new work tree and set cloud up in there and get it working on a thing.

01:01:11.680 --> 01:01:18.220
And so I have found that I can only, I need to limit myself to two or three work trees because any more than that, I start losing context.

01:01:18.220 --> 01:01:19.960
And now I know what the LLM is.

01:01:20.300 --> 01:01:21.000
Yeah, exactly.

01:01:21.240 --> 01:01:28.460
If you over, overdo it, it's, you just send off five agents and don't look like that's how you end up like, oh, we have kind of like bugs in our code about architecture.

01:01:28.600 --> 01:01:30.000
Well, you never look at it.

01:01:30.280 --> 01:01:35.520
It's like, we got the super energetic, super smart intern and we kicked him off and said, go on that feature.

01:01:35.660 --> 01:01:37.780
But you know, they need guidance, right?

01:01:38.020 --> 01:01:40.700
All the tests are passing because I changed all the tests to pass.

01:01:40.860 --> 01:01:41.280
I know.

01:01:41.440 --> 01:01:43.440
The problematic data has been removed from the database.

01:01:43.640 --> 01:01:44.080
It works now.

01:01:45.240 --> 01:01:46.080
Why is it empty?

01:01:46.080 --> 01:01:46.480
Yeah.

01:01:48.320 --> 01:01:49.780
Back to your backup comments.

01:01:50.220 --> 01:01:55.300
Honestly, I'm having like an insane amount of productivity with cloud code and with AI and stuff.

01:01:55.500 --> 01:01:57.200
But it's an engineering skill.

01:01:57.360 --> 01:01:59.780
It is not just, let's fire it up and ask for it.

01:01:59.820 --> 01:02:07.500
Like one of the things I'm doing lately that I'm really appreciating is going through like a planning session, which I know a lot of people do that and like talk about it.

01:02:07.620 --> 01:02:22.220
But, and now, if you have the GitHub CLI installed, just the GH thing, you can tell it, hey, create, you know, instead of just running this plan, create a GitHub issue of this plan, write all the details in GitHub and then your next comment

01:02:22.220 --> 01:02:26.680
can be, let's work on issue 127 and it'll go work on it when it gets done.

01:02:26.780 --> 01:02:29.600
Like, let's make a retrospective comment on the issue.

01:02:29.740 --> 01:02:31.960
Let's create a PR that closes that issue.

01:02:32.120 --> 01:02:41.860
That's, you're like, there's some really interesting team dynamics that you can put in there that, you know, talking to a chat box is not covered, but if you know what, you know what to ask for.

01:02:41.860 --> 01:02:48.780
Yeah, I'm really inspired by Martin and Adam because both of them in one way or another have, let me take a step back.

01:02:48.980 --> 01:02:50.640
They, I mentioned the event modeling diagram.

01:02:51.160 --> 01:03:00.900
It is a visual diagram that really has a reduced visual language and what was mind-blowing to us a couple years ago was that AI understands it.

01:03:01.120 --> 01:03:07.860
And so, the fact that you can essentially say like, here's the diagram, can you implement the slice and it can get you from, well, let me take a step back.

01:03:08.140 --> 01:03:16.220
Martin and Adam have both had successful research spikes where they took an event modeling diagram.

01:03:16.360 --> 01:03:23.280
Actually, no, they even did, what they did even worse was they started with a conversation with a client and recorded it, created the transfer.

01:03:23.280 --> 01:03:24.120
They generated the diagram.

01:03:24.400 --> 01:03:38.100
Generated the diagram and then generated code from the diagram that didn't solve everything but got it, I think, 80 or 85% the way they're in hours from, you know, like cutting months of work down to weeks is impressive.

01:03:38.360 --> 01:03:52.700
And I've had some similar, you know, I'm still working on my personal one because like, I just, you know, after work, I just tend to shut down my computers and I'm not like dedicated to like really going at it but like, I found some really incredible benefits

01:03:52.700 --> 01:03:53.580
of doing something like that.

01:03:53.680 --> 01:03:54.140
that's awesome.

01:03:54.380 --> 01:03:55.900
I created this open source project.

01:03:56.100 --> 01:04:05.420
I mean, it's more source open, whatever, it's not really a project but I called it Python Package Guides for Agents and all the projects that I work on, I'll go and download the source and the documentation.

01:04:05.840 --> 01:04:19.880
So like, if I'm working on disk cache, I'll like literally clone it, clone the documentation and then make Claude write a super detailed, like, not use their documentation or its old version but like, have it like legit, write down examples, study the source code, study the documentation,

01:04:20.280 --> 01:04:34.000
source code like trumps documentation because if the docs are out of date and so on and then I'll drop, you know, if I'm using like two of these like maybe data classes and disk cache, I'll drop those things into my project and tell Claude about them and that's been a pretty neat thing to do as well.

01:04:34.100 --> 01:04:34.300
Yeah.

01:04:34.500 --> 01:04:38.320
But I want to leave this portion of our conversation with an incredible joke.

01:04:38.860 --> 01:04:39.220
Okay.

01:04:39.500 --> 01:04:39.860
Okay.

01:04:40.120 --> 01:04:42.120
Just because I feel like this has to be said right now.

01:04:42.300 --> 01:04:48.740
It's just so, the joke, this is the word copilot, it could be Claude, it could be Codex, it could be Chat, whatever, like just AI, right?

01:04:48.960 --> 01:04:49.880
Friends outside of tech.

01:04:50.220 --> 01:04:51.340
Lol, copilot is dumb.

01:04:51.500 --> 01:04:52.020
Friends in tech.

01:04:52.020 --> 01:04:52.680
In tech.

01:04:52.940 --> 01:04:55.500
I just bought iodine tablets and I've made an offer in land of state.

01:04:55.580 --> 01:05:01.380
My supplies of antibiotics and potable water are sufficient but I need to set up for the hydroponics to make it through the first few years.

01:05:01.580 --> 01:05:03.020
Like I feel like that's where we are, you know?

01:05:03.460 --> 01:05:05.240
Yeah, yeah, totally, totally.

01:05:06.120 --> 01:05:10.040
And that maybe also sums up your meetup as well.

01:05:10.340 --> 01:05:11.260
Yeah, yeah, yeah.

01:05:11.560 --> 01:05:12.520
Yeah, absolutely.

01:05:12.760 --> 01:05:16.660
It's quite a spectrum both of Friends outside tech and inside tech.

01:05:17.000 --> 01:05:17.460
Yeah, exactly.

01:05:17.620 --> 01:05:19.860
Like it's more like believers and non-believers.

01:05:19.980 --> 01:05:20.680
I'm not really sure.

01:05:20.680 --> 01:05:21.400
All right.

01:05:21.400 --> 01:05:22.460
Final Call to Action.

01:05:22.580 --> 01:05:23.720
What do we got here?

01:05:24.000 --> 01:05:24.780
People are interested.

01:05:24.920 --> 01:05:25.500
They want to get started.

01:05:25.600 --> 01:05:26.080
What do you tell them?

01:05:26.680 --> 01:05:28.580
Get your ebook, your free ebook that you put up?

01:05:28.580 --> 01:05:28.960
That's right.

01:05:29.260 --> 01:05:32.320
Yeah, so my website is everydaysuperpowers.dev.

01:05:32.600 --> 01:05:46.260
If you want an ebook that kind of introduces you into event sourcing and kind of gives you kind of this kind of fundamental background and a couple other things, go to everydaysuperpowers.dev slash es intro and it'll take you right there.

01:05:46.260 --> 01:05:54.720
I'm on Mastodon mostly, but I'm also watchbluesky and sometimes x underscore chrismay on all of those.

01:05:55.120 --> 01:05:57.680
With Mastodon, I think I'm on fosstodon.org.

01:05:57.880 --> 01:05:58.340
What else?

01:05:59.080 --> 01:06:01.580
I mentioned everydaysuperpowers, so that's...

01:06:01.580 --> 01:06:06.180
I also have a Discord from there too, so if you go through my website, you can see how you can join that.

01:06:07.040 --> 01:06:07.200
Sweet.

01:06:07.320 --> 01:06:08.940
Maybe check out the event sourcing library.

01:06:09.280 --> 01:06:09.840
100%.

01:06:09.840 --> 01:06:10.260
For them people.

01:06:10.260 --> 01:06:10.700
Yeah.

01:06:10.860 --> 01:06:11.080
Yeah.

01:06:11.340 --> 01:06:12.400
And if you...

01:06:12.400 --> 01:06:13.780
Oh, oh, the...

01:06:13.780 --> 01:06:21.360
Martin and Adam have a podcast called the Event Modeling and Event Sourcing Podcast, which is verbosely named, but it also is really great.

01:06:21.540 --> 01:06:25.260
You know, this is how I learn just from these great people, you know.

01:06:25.460 --> 01:06:25.780
There you go.

01:06:26.000 --> 01:06:27.560
Just kind of every...

01:06:27.560 --> 01:06:30.920
Almost every week talking about patterns they do and stuff like that.

01:06:30.960 --> 01:06:36.960
They also talk about a bunch of other stuff that isn't relevant, but I've learned so much from listening to them and they also have Discords.

01:06:37.180 --> 01:06:37.360
So go ahead.

01:06:37.500 --> 01:06:37.720
Cool.

01:06:37.820 --> 01:06:38.820
I'm honestly impressed.

01:06:39.140 --> 01:06:41.180
Like an entire podcast on a single design pattern.

01:06:41.300 --> 01:06:41.640
Let's go.

01:06:42.360 --> 01:06:43.640
That's commitment to it.

01:06:43.880 --> 01:06:44.100
Yeah.

01:06:44.420 --> 01:06:44.640
Yeah.

01:06:44.740 --> 01:06:45.480
And it's incredible.

01:06:45.660 --> 01:06:50.440
I mean, as someone who has played the board game and really enjoys it, it's amazing.

01:06:51.540 --> 01:06:56.660
Well, Chris, I really appreciate you coming on here and sharing all your experience and excitement and all the things.

01:06:56.940 --> 01:06:57.440
Great to talk to you.

01:06:57.680 --> 01:06:57.960
Likewise.

01:06:58.120 --> 01:06:58.720
Thanks for having me.

01:06:59.780 --> 01:07:02.140
This has been another episode of Talk Python To Me.

01:07:02.280 --> 01:07:03.260
Thank you to our sponsors.

01:07:03.440 --> 01:07:04.720
Be sure to check out what they're offering.

01:07:04.900 --> 01:07:06.280
It really helps support the show.

01:07:06.780 --> 01:07:09.340
This episode is sponsored by Sentry's Sear.

01:07:09.340 --> 01:07:12.120
If you're tired of debugging in the dark, give Sear a try.

01:07:12.620 --> 01:07:17.920
There are plenty of AI tools that help you write code, but Sentry's Sear is built to help you fix it when it breaks.

01:07:18.460 --> 01:07:26.420
Visit talkpython.fm/sentry and use the code talkpython26, all one word, no spaces, for $100 in Sentry credits.

01:07:27.220 --> 01:07:30.800
And it's brought to you by Temporal, durable workflows for Python.

01:07:31.080 --> 01:07:37.780
Write your workflows as normal Python code and Temporal ensures they run reliably, even across crashes and restarts.

01:07:38.280 --> 01:07:41.080
Get started at talkpython.fm/Temporal.

01:07:41.800 --> 01:07:54.220
If you or your team needs to learn Python, we have over 270 hours of beginner and advanced courses on topics ranging from complete beginners to async code, Flask, Django, HTMX, and even LLMs.

01:07:54.460 --> 01:07:56.880
Best of all, there's no subscription in sight.

01:07:57.320 --> 01:07:59.060
Browse the catalog at talkpython.fm.

01:07:59.720 --> 01:08:04.400
And if you're not already subscribed to the show on your favorite podcast player, what are you waiting for?

01:08:04.400 --> 01:08:06.880
Just search for Python in your podcast player.

01:08:06.980 --> 01:08:07.860
We should be right at the top.

01:08:08.000 --> 01:08:11.160
If you enjoyed that geeky rap song, you can download the full track.

01:08:11.260 --> 01:08:13.180
The link is actually in your podcast blur show notes.

01:08:13.760 --> 01:08:15.300
This is your host, Michael Kennedy.

01:08:15.500 --> 01:08:16.800
Thank you so much for listening.

01:08:16.980 --> 01:08:17.760
I really appreciate it.

01:08:18.180 --> 01:08:18.940
I'll see you next time.

01:08:18.940 --> 01:08:48.940
to the show 

01:08:48.940 --> 01:09:18.920
Thank you.