WEBVTT

1
00:00:00.120 --> 00:00:04.080
<v Speaker 1>It's Black Friday. You spent maybe an hour hunting down

2
00:00:04.160 --> 00:00:08.119
<v Speaker 1>deals on this massive retail site and you finally, you know,

3
00:00:08.119 --> 00:00:09.080
<v Speaker 1>you finally click check out.

4
00:00:09.119 --> 00:00:11.320
<v Speaker 2>Oh yeah, the pressure's totally on, right.

5
00:00:11.240 --> 00:00:15.759
<v Speaker 1>The pressure's on, and the shopping cart just freezes, or

6
00:00:15.880 --> 00:00:19.760
<v Speaker 1>even worse, the page refreshes and just drops your items entirely.

7
00:00:19.640 --> 00:00:21.600
<v Speaker 2>Which is just the worst feeling.

8
00:00:21.760 --> 00:00:24.359
<v Speaker 1>It really is. If you're anything like me, you probably

9
00:00:24.399 --> 00:00:26.559
<v Speaker 1>just stare at the screen and pure frustration.

10
00:00:26.839 --> 00:00:29.879
<v Speaker 2>I mean, it is a totally broken digital promise, right,

11
00:00:29.920 --> 00:00:32.679
<v Speaker 2>You're left completely stranded by a system that just couldn't

12
00:00:32.719 --> 00:00:36.359
<v Speaker 2>handle the reality of, you know, a massive traffic spike.

13
00:00:36.520 --> 00:00:40.000
<v Speaker 1>Yeah, exactly. And yet there are apps and systems out

14
00:00:40.000 --> 00:00:43.359
<v Speaker 1>there that actually don't do this, systems that handle millions

15
00:00:43.359 --> 00:00:45.799
<v Speaker 1>of users at the exact same time without even breaking

16
00:00:45.799 --> 00:00:46.240
<v Speaker 1>a sweat.

17
00:00:46.359 --> 00:00:47.799
<v Speaker 2>Yeah, they just keep humming along.

18
00:00:47.960 --> 00:00:50.240
<v Speaker 1>So today our mission is to figure out the secret

19
00:00:50.320 --> 00:00:53.439
<v Speaker 1>architecture behind those rock solid platforms. We are going to

20
00:00:53.479 --> 00:00:56.320
<v Speaker 1>explore the concepts in a deep dive on functional and

21
00:00:56.399 --> 00:00:59.719
<v Speaker 1>reactive domain modeling by Debasish Ghosh.

22
00:01:00.079 --> 00:01:01.920
<v Speaker 2>Such a great source text, it really is.

23
00:01:02.320 --> 00:01:04.200
<v Speaker 1>And the goal today is to give you the listener

24
00:01:04.239 --> 00:01:07.519
<v Speaker 1>a bit of a shortcut to understanding how modern software

25
00:01:07.719 --> 00:01:11.799
<v Speaker 1>is actually built by merging three really powerful ideas.

26
00:01:11.879 --> 00:01:17.200
<v Speaker 2>Right, So that's domain driven design, functional programming, and reactive architecture.

27
00:01:16.680 --> 00:01:21.079
<v Speaker 1>Exactly, Because I mean, while building massive global systems is

28
00:01:21.159 --> 00:01:25.359
<v Speaker 1>inherently complex, the big secret in software engineering right now

29
00:01:25.680 --> 00:01:28.120
<v Speaker 1>is that if we start treating our code a little

30
00:01:28.159 --> 00:01:29.480
<v Speaker 1>bit more like pure.

31
00:01:29.239 --> 00:01:32.560
<v Speaker 2>Mathematics, it can actually save us from the total chaos

32
00:01:32.640 --> 00:01:35.599
<v Speaker 2>of the real world, which sounds crazy, but it's true.

33
00:01:35.799 --> 00:01:37.719
<v Speaker 1>It does sound crazy. But before we can even start

34
00:01:37.760 --> 00:01:41.239
<v Speaker 1>talking to pure math or you know, preventing server crashes,

35
00:01:41.319 --> 00:01:42.879
<v Speaker 1>we kind of figure out what it is we are

36
00:01:42.920 --> 00:01:45.799
<v Speaker 1>actually building, right. You need a blueprint, We need a blueprint,

37
00:01:45.840 --> 00:01:49.040
<v Speaker 1>and in this architecture, that blueprint is called a domain model,

38
00:01:49.239 --> 00:01:51.959
<v Speaker 1>which is built using domain driven design or DDD.

39
00:01:52.319 --> 00:01:54.280
<v Speaker 2>Yeah, so think of a domain model as a direct

40
00:01:54.319 --> 00:01:57.040
<v Speaker 2>translation of how a business actually works in the real world,

41
00:01:57.319 --> 00:01:58.840
<v Speaker 2>but translated into software.

42
00:01:58.920 --> 00:01:59.760
<v Speaker 1>Okay, makes sense.

43
00:02:00.120 --> 00:02:03.640
<v Speaker 2>But to do that translation accurately, Domain driven design says

44
00:02:03.680 --> 00:02:07.120
<v Speaker 2>you absolutely must start with what they call a ubiquitous language.

45
00:02:07.280 --> 00:02:11.879
<v Speaker 1>Ubiquitous language meaning meaning everyone involved from the CEO to

46
00:02:11.919 --> 00:02:14.639
<v Speaker 1>the junior developer speaks the exact same way.

47
00:02:14.680 --> 00:02:17.719
<v Speaker 2>That's the core of it. Yeah, it means using actual

48
00:02:17.759 --> 00:02:20.879
<v Speaker 2>business terms directly in the code itself. So if you

49
00:02:20.960 --> 00:02:23.800
<v Speaker 2>are building a banking app, developers shouldn't be naming things

50
00:02:23.800 --> 00:02:27.240
<v Speaker 2>with like generic programmer jurgen.

51
00:02:27.039 --> 00:02:29.080
<v Speaker 1>Like user data object or whatever.

52
00:02:29.080 --> 00:02:33.360
<v Speaker 2>Exactly, or transaction hash. You use the vocabulary of the domain.

53
00:02:33.719 --> 00:02:37.439
<v Speaker 2>You use terms like debit, credit, portfolio account.

54
00:02:37.680 --> 00:02:37.879
<v Speaker 1>Right.

55
00:02:38.000 --> 00:02:41.360
<v Speaker 2>The real acid test is whether a business expert, like

56
00:02:41.400 --> 00:02:44.560
<v Speaker 2>an actual working banker, could sit down, look at the

57
00:02:44.560 --> 00:02:46.719
<v Speaker 2>code structure and theoretically understand the.

58
00:02:46.639 --> 00:02:51.199
<v Speaker 1>Workflow because you eliminate that really dangerous translation layer between

59
00:02:51.199 --> 00:02:53.560
<v Speaker 1>the business folks and the programmers, which.

60
00:02:53.360 --> 00:02:55.520
<v Speaker 2>Is where so many bugs usually hide. To be honest,

61
00:02:55.520 --> 00:02:56.280
<v Speaker 2>we totally.

62
00:02:56.120 --> 00:02:58.240
<v Speaker 1>And to build this domain model we rely on a

63
00:02:58.280 --> 00:03:01.319
<v Speaker 1>few specific building blocks, the main ones being entities and

64
00:03:01.400 --> 00:03:02.199
<v Speaker 1>value objects.

65
00:03:02.520 --> 00:03:04.960
<v Speaker 2>Yeah, and the distinction between those two is one of

66
00:03:05.000 --> 00:03:08.520
<v Speaker 2>the most fundamental concepts in domain driven design. So let's

67
00:03:08.520 --> 00:03:09.560
<v Speaker 2>look at entities first.

68
00:03:09.719 --> 00:03:10.080
<v Speaker 1>Okay.

69
00:03:10.280 --> 00:03:13.599
<v Speaker 2>An entity is an object that has a unique identity

70
00:03:13.680 --> 00:03:18.120
<v Speaker 2>that never ever changes, even if its internal attributes due

71
00:03:18.159 --> 00:03:20.360
<v Speaker 2>like a bank account. An account is a perfect example.

72
00:03:20.400 --> 00:03:22.800
<v Speaker 2>It has a unique account number. You might change the

73
00:03:22.879 --> 00:03:25.039
<v Speaker 2>name on the account, or you know, the balance will

74
00:03:25.039 --> 00:03:28.759
<v Speaker 2>obviously fluctuate but it is still fundamentally the same account

75
00:03:28.759 --> 00:03:30.240
<v Speaker 2>because the ID remains the same.

76
00:03:30.280 --> 00:03:33.360
<v Speaker 1>Okay, let's unpack this for a second. An entity is

77
00:03:33.439 --> 00:03:35.639
<v Speaker 1>like it's like a car with a VEN number.

78
00:03:35.719 --> 00:03:36.400
<v Speaker 2>Oh I like that.

79
00:03:36.599 --> 00:03:38.840
<v Speaker 1>Yeah, you can paint the car neon green, you can

80
00:03:38.919 --> 00:03:41.599
<v Speaker 1>completely change the tires, you can swap out the radio,

81
00:03:42.120 --> 00:03:45.120
<v Speaker 1>but legally, because of that gin, it is still the

82
00:03:45.240 --> 00:03:46.280
<v Speaker 1>exact same car.

83
00:03:46.520 --> 00:03:49.080
<v Speaker 2>That is a perfect analogy. Now contrast that car with

84
00:03:49.120 --> 00:03:50.120
<v Speaker 2>a value object.

85
00:03:50.240 --> 00:03:50.439
<v Speaker 1>Right.

86
00:03:50.479 --> 00:03:53.280
<v Speaker 2>A value object has absolutely no identity of its own.

87
00:03:53.360 --> 00:03:55.919
<v Speaker 2>It is defined entirely by its value, which means it

88
00:03:56.000 --> 00:03:58.120
<v Speaker 2>is completely immutable. You cannot change it.

89
00:03:58.400 --> 00:04:00.919
<v Speaker 1>So a value object would be like a twenty dollars bill.

90
00:04:01.199 --> 00:04:03.800
<v Speaker 1>You don't care which exact twenty dollars bill you have

91
00:04:03.879 --> 00:04:06.319
<v Speaker 1>in your wallet. I mean, you aren't tracking the serial number.

92
00:04:06.560 --> 00:04:08.639
<v Speaker 1>You only care that the value is twenty dollars.

93
00:04:08.759 --> 00:04:11.560
<v Speaker 2>Right, if you exchange it for two tens, you haven't

94
00:04:11.599 --> 00:04:14.280
<v Speaker 2>altered your twenty dollar bill. You've swapped it for something

95
00:04:14.439 --> 00:04:18.759
<v Speaker 2>entirely new, got it? Or think about a residential address

96
00:04:18.800 --> 00:04:21.480
<v Speaker 2>in a banking system. An address is really just a

97
00:04:21.519 --> 00:04:25.560
<v Speaker 2>collection of values street, city, zip code. If you change

98
00:04:25.600 --> 00:04:28.759
<v Speaker 2>the zip code on an address, you haven't updated the.

99
00:04:28.720 --> 00:04:31.920
<v Speaker 1>Address, You've created a completely different address exactly.

100
00:04:32.399 --> 00:04:35.560
<v Speaker 2>Because value objects are defined by their values and can't

101
00:04:35.560 --> 00:04:39.360
<v Speaker 2>be modified, they're incredibly safe. You can pass them around

102
00:04:39.360 --> 00:04:42.560
<v Speaker 2>the system freely without worrying about keeping track of some

103
00:04:42.680 --> 00:04:45.279
<v Speaker 2>unique ID or accidentally altering them.

104
00:04:45.399 --> 00:04:48.639
<v Speaker 1>Okay, so we have the raw materials, the entities and

105
00:04:48.680 --> 00:04:51.639
<v Speaker 1>the value objects, but they just sort of sit there, Right,

106
00:04:52.120 --> 00:04:54.680
<v Speaker 1>how do we actually make them do something, like, say,

107
00:04:55.079 --> 00:04:56.759
<v Speaker 1>transfer money between two accounts.

108
00:04:56.839 --> 00:05:00.680
<v Speaker 2>That's where the third element comes in, which are services. Yeah,

109
00:05:00.720 --> 00:05:04.519
<v Speaker 2>services are the higher level actions. They represent the actual

110
00:05:04.560 --> 00:05:08.439
<v Speaker 2>behaviors where multiple entities and value objects interact.

111
00:05:08.639 --> 00:05:10.879
<v Speaker 1>So like the actual transfer process.

112
00:05:10.519 --> 00:05:13.000
<v Speaker 2>Right, a service would be the action of transferring funds.

113
00:05:13.399 --> 00:05:16.040
<v Speaker 2>It's a coordinated operation that involves, you know, pulling from

114
00:05:16.120 --> 00:05:19.800
<v Speaker 2>one account entity, adding to another account entity, and swapping

115
00:05:19.800 --> 00:05:21.959
<v Speaker 2>out the money value objects inside them.

116
00:05:22.160 --> 00:05:25.759
<v Speaker 1>The implication of that structure is really clean, but there

117
00:05:25.800 --> 00:05:27.600
<v Speaker 1>is a nuance to it that caught my eye in

118
00:05:27.639 --> 00:05:31.600
<v Speaker 1>the book. The definitions of these objects aren't actually universal,

119
00:05:31.639 --> 00:05:32.160
<v Speaker 1>are they.

120
00:05:32.279 --> 00:05:33.120
<v Speaker 2>No, not at all.

121
00:05:33.160 --> 00:05:36.120
<v Speaker 1>They depend heavily on something called a bounded context.

122
00:05:36.399 --> 00:05:39.800
<v Speaker 2>The bounded context is so crucial. The meaning of an

123
00:05:39.800 --> 00:05:44.120
<v Speaker 2>object changes entirely depending on the specific module or context

124
00:05:44.199 --> 00:05:46.519
<v Speaker 2>you are working in. Right, Take that address we just

125
00:05:46.560 --> 00:05:50.079
<v Speaker 2>talked about. In our personal banking context, an address is

126
00:05:50.240 --> 00:05:52.639
<v Speaker 2>just a value object. We only care about the text

127
00:05:52.759 --> 00:05:53.959
<v Speaker 2>to print on a bank.

128
00:05:53.759 --> 00:05:56.199
<v Speaker 1>Statement, right, just a string of letters and numbers.

129
00:05:56.319 --> 00:05:58.680
<v Speaker 2>But imagine you are building a mapping application, like a

130
00:05:58.720 --> 00:06:00.120
<v Speaker 2>GPS routing system.

131
00:06:00.160 --> 00:06:03.639
<v Speaker 1>Oh wow, In that context, the address isn't just text

132
00:06:03.680 --> 00:06:04.639
<v Speaker 1>on the page anymore.

133
00:06:04.920 --> 00:06:09.560
<v Speaker 2>Exactly, in a mapping context, that same address suddenly becomes

134
00:06:09.600 --> 00:06:12.600
<v Speaker 2>an entity. It gets its own unique idea in the database,

135
00:06:12.639 --> 00:06:15.040
<v Speaker 2>it gets GPS coordinates, it gets a whole life cycle.

136
00:06:15.439 --> 00:06:17.480
<v Speaker 2>Context totally dictates the design.

137
00:06:17.639 --> 00:06:20.040
<v Speaker 1>So now we have our blueprint, we have our language,

138
00:06:20.040 --> 00:06:22.560
<v Speaker 1>our context, and our objects. But if we go back

139
00:06:22.560 --> 00:06:24.439
<v Speaker 1>to that Black Friday scenario.

140
00:06:24.160 --> 00:06:25.920
<v Speaker 2>Freezing shopping cart.

141
00:06:25.720 --> 00:06:28.920
<v Speaker 1>Yeah, how do these entities interact without the server just

142
00:06:29.000 --> 00:06:32.040
<v Speaker 1>catching on fire when a million people log in at once?

143
00:06:32.920 --> 00:06:34.720
<v Speaker 1>I think we need to talk about the shift from

144
00:06:34.839 --> 00:06:39.399
<v Speaker 1>traditional object oriented design to functional programming. Yeah.

145
00:06:39.439 --> 00:06:42.160
<v Speaker 2>To understand why that shift is happening across the industry,

146
00:06:42.399 --> 00:06:44.319
<v Speaker 2>we have to confront the ghost in the machine of

147
00:06:44.360 --> 00:06:46.879
<v Speaker 2>older architectures, which is mutable state.

148
00:06:47.160 --> 00:06:47.920
<v Speaker 1>Mutable state.

149
00:06:48.120 --> 00:06:51.199
<v Speaker 2>Right, for decades, the standard way to write software relied

150
00:06:51.279 --> 00:06:54.600
<v Speaker 2>heavily on changing data in place. You have an object,

151
00:06:54.680 --> 00:06:57.079
<v Speaker 2>say an account with a balance of one thousand dollars.

152
00:06:57.399 --> 00:07:00.519
<v Speaker 2>When someone withdraws money, the code reaches into that exact

153
00:07:00.600 --> 00:07:04.439
<v Speaker 2>object memory and mutates the balance down to nine hundred, which.

154
00:07:04.240 --> 00:07:06.600
<v Speaker 1>Honestly, it sounds totally logical. You take money out, the

155
00:07:06.680 --> 00:07:07.399
<v Speaker 1>number goes down.

156
00:07:07.720 --> 00:07:13.120
<v Speaker 2>It does until you introduce concurrency. Think about Payday. Millions

157
00:07:13.120 --> 00:07:17.279
<v Speaker 2>of users are accessing the same banking system simultaneously. If

158
00:07:17.319 --> 00:07:21.839
<v Speaker 2>you rely on mutable state, you have an absolute concurrency nightmare.

159
00:07:21.519 --> 00:07:23.399
<v Speaker 1>Because everyone is trying to change things at once.

160
00:07:23.680 --> 00:07:27.480
<v Speaker 2>Imagine two separate server threads trying to access and mutate

161
00:07:27.519 --> 00:07:30.800
<v Speaker 2>that exact same account balance at the exact same millisecond.

162
00:07:31.319 --> 00:07:34.040
<v Speaker 2>Thread A tries to withdraw one hundred dollars, while THREADBE

163
00:07:34.040 --> 00:07:36.800
<v Speaker 2>tries to deposit five hundred. Oh Now, if they're both

164
00:07:36.839 --> 00:07:40.000
<v Speaker 2>trying to overwrite the state in place, they can collide,

165
00:07:40.240 --> 00:07:43.120
<v Speaker 2>overwrite each other and cause massive data corruption.

166
00:07:43.319 --> 00:07:46.319
<v Speaker 1>The system panics, the math gets wrong, and somebody loses

167
00:07:46.319 --> 00:07:47.000
<v Speaker 1>a lot of money.

168
00:07:47.079 --> 00:07:50.959
<v Speaker 2>Exactly, It is incredibly difficult to reason about code when

169
00:07:51.000 --> 00:07:54.480
<v Speaker 2>the data is constantly shifting underneath you. So the functional

170
00:07:54.480 --> 00:07:57.240
<v Speaker 2>programming approach takes a pretty radical stance. We kill the

171
00:07:57.319 --> 00:08:02.199
<v Speaker 2>mutable state entirely. We completely separate state from behavior. State

172
00:08:02.319 --> 00:08:06.120
<v Speaker 2>is stored in what are called algebraic data types or ADTs,

173
00:08:06.160 --> 00:08:10.480
<v Speaker 2>which are strictly immutable. Behavior is handled separately by pure functions.

174
00:08:10.759 --> 00:08:13.160
<v Speaker 1>Okay, let me stop you right there, because algebraic data

175
00:08:13.160 --> 00:08:18.319
<v Speaker 1>types sounds incredibly intimidating. What makes a piece of data algebraic?

176
00:08:18.600 --> 00:08:20.839
<v Speaker 2>I know it sounds super academic, but it just means

177
00:08:20.839 --> 00:08:24.199
<v Speaker 2>you can struct your data types using the mathematical concepts

178
00:08:24.199 --> 00:08:25.319
<v Speaker 2>of sums and products.

179
00:08:25.439 --> 00:08:26.319
<v Speaker 1>Sums and products.

180
00:08:26.399 --> 00:08:29.560
<v Speaker 2>Yeah, So, a product type is an A and D relationship,

181
00:08:29.920 --> 00:08:33.879
<v Speaker 2>a user profile is a name and D an email

182
00:08:33.919 --> 00:08:36.440
<v Speaker 2>and the a password that makes sense, and a sum

183
00:08:36.440 --> 00:08:40.039
<v Speaker 2>type is an ore relationship. A payment method is either

184
00:08:40.080 --> 00:08:42.879
<v Speaker 2>a credit card or a bank transfer or a gift card,

185
00:08:43.000 --> 00:08:46.440
<v Speaker 2>oh icee. By defining data this strictly, the compiler can

186
00:08:46.480 --> 00:08:49.879
<v Speaker 2>actually check your logic mathematically to ensure you've handled every

187
00:08:49.960 --> 00:08:54.440
<v Speaker 2>possible scenario. And crucially, once these ADTs are created, they

188
00:08:54.480 --> 00:08:55.320
<v Speaker 2>cannot be changed.

189
00:08:55.399 --> 00:08:57.120
<v Speaker 1>Wait, hang on, I'm not letting that go. If I

190
00:08:57.200 --> 00:09:00.240
<v Speaker 1>deposit one hundred dollars into my account and the account

191
00:09:00.279 --> 00:09:04.360
<v Speaker 1>ADT is mathematically immutable, meaning the code literally cannot change it.

192
00:09:04.879 --> 00:09:06.440
<v Speaker 1>How does my balance actually go up?

193
00:09:06.720 --> 00:09:07.519
<v Speaker 2>It's a great question.

194
00:09:07.559 --> 00:09:09.240
<v Speaker 1>I might have stuck with my old balance forever.

195
00:09:09.639 --> 00:09:12.480
<v Speaker 2>No. No, The answer is that instead of mutating the

196
00:09:12.600 --> 00:09:17.000
<v Speaker 2>existing account object, the function uses a smart constructor to

197
00:09:17.120 --> 00:09:19.559
<v Speaker 2>generate a brand new copy of the account, but with

198
00:09:19.600 --> 00:09:20.720
<v Speaker 2>the updated balance.

199
00:09:20.759 --> 00:09:22.720
<v Speaker 1>I still don't get how that works at scale, though,

200
00:09:22.919 --> 00:09:25.720
<v Speaker 1>How do you mean? Well, if Amazon is processing a

201
00:09:25.759 --> 00:09:28.919
<v Speaker 1>billion transactions an hour and they have to generate a

202
00:09:29.080 --> 00:09:33.159
<v Speaker 1>brand new clone copy of a massive shopping cart object

203
00:09:33.519 --> 00:09:36.320
<v Speaker 1>every single time I add a single pair of socks,

204
00:09:36.639 --> 00:09:38.879
<v Speaker 1>that has to blow up the servers. Oh right, The

205
00:09:38.919 --> 00:09:42.039
<v Speaker 1>memory consumption would be astronomical. What is the code actually

206
00:09:42.080 --> 00:09:43.360
<v Speaker 1>doing behind the scenes.

207
00:09:43.440 --> 00:09:47.320
<v Speaker 2>You're touching on Honestly the biggest hurdle for people moving

208
00:09:47.360 --> 00:09:50.159
<v Speaker 2>to functional programming. It would blow up the memory if

209
00:09:50.200 --> 00:09:53.399
<v Speaker 2>it were doing a naive total clone, right, But it

210
00:09:53.440 --> 00:09:56.000
<v Speaker 2>doesn't do that. It uses something called structural sharing.

211
00:09:56.120 --> 00:09:57.519
<v Speaker 1>Structural sharing, how does that work?

212
00:09:57.600 --> 00:10:00.399
<v Speaker 2>Think of your shopping cart data as a giant tree

213
00:10:00.440 --> 00:10:05.000
<v Speaker 2>with many branches. You have branches for electronics, clothing, shipping details,

214
00:10:05.039 --> 00:10:05.480
<v Speaker 2>and so on.

215
00:10:05.759 --> 00:10:06.759
<v Speaker 1>Okay, if you.

216
00:10:06.720 --> 00:10:09.320
<v Speaker 2>Add a pair of socks, the system doesn't copy the

217
00:10:09.360 --> 00:10:11.960
<v Speaker 2>whole tree. It creates a new root of the tree,

218
00:10:12.200 --> 00:10:15.480
<v Speaker 2>and it creates the one new tiny branch for the socks.

219
00:10:15.799 --> 00:10:16.360
<v Speaker 1>Oh wow.

220
00:10:16.600 --> 00:10:19.200
<v Speaker 2>But for all the other branches, the electronics, the shipping,

221
00:10:19.279 --> 00:10:21.720
<v Speaker 2>the new tree just points back to the exact same

222
00:10:21.759 --> 00:10:23.879
<v Speaker 2>branches from the old tree in memory.

223
00:10:24.039 --> 00:10:28.120
<v Speaker 1>Oh so, because nothing in the old tree can ever

224
00:10:28.159 --> 00:10:31.200
<v Speaker 1>be mutated, it's perfectly safe for the new tree to

225
00:10:31.240 --> 00:10:32.840
<v Speaker 1>share those older parts exactly.

226
00:10:33.200 --> 00:10:37.080
<v Speaker 2>It's incredibly memory efficient. You are only allocating memory for

227
00:10:37.120 --> 00:10:38.919
<v Speaker 2>the tiny piece that actually changed.

228
00:10:39.080 --> 00:10:39.960
<v Speaker 1>That is brilliant.

229
00:10:40.240 --> 00:10:44.240
<v Speaker 2>But the massive benefit is concurrency. Because that old tree

230
00:10:44.279 --> 00:10:48.200
<v Speaker 2>is never overwritten, it remains perfectly safe. Any number of

231
00:10:48.240 --> 00:10:51.039
<v Speaker 2>concurrent threads can be reading that old state at the

232
00:10:51.080 --> 00:10:55.080
<v Speaker 2>exact same time without any fear of data corruption. The

233
00:10:55.120 --> 00:10:58.080
<v Speaker 2>whole fear of concurrency completely vanishes.

234
00:10:57.919 --> 00:11:00.639
<v Speaker 1>Because nobody is fighting over the same chock. They all

235
00:11:00.639 --> 00:11:02.919
<v Speaker 1>get their own brand new chalkboard and they just share

236
00:11:02.960 --> 00:11:03.639
<v Speaker 1>the erasers.

237
00:11:03.759 --> 00:11:04.320
<v Speaker 2>I love that.

238
00:11:04.559 --> 00:11:07.759
<v Speaker 1>Yeah. So, because our data is totally immutable, something really

239
00:11:07.759 --> 00:11:10.200
<v Speaker 1>magical happens to the functions themselves. They start acting like

240
00:11:10.279 --> 00:11:11.159
<v Speaker 1>high school algebra.

241
00:11:11.399 --> 00:11:15.720
<v Speaker 2>Yes, and this brings us to a concept called referential transparency.

242
00:11:15.039 --> 00:11:16.159
<v Speaker 1>Which sounds intense.

243
00:11:16.200 --> 00:11:18.759
<v Speaker 2>Again, it's simpler than it sounds, I promise. Think back

244
00:11:18.759 --> 00:11:23.000
<v Speaker 2>to basic math y equals f of x. If your

245
00:11:23.000 --> 00:11:25.919
<v Speaker 2>function is to square a number and you input three,

246
00:11:26.200 --> 00:11:27.519
<v Speaker 2>the output is always nine.

247
00:11:27.759 --> 00:11:27.919
<v Speaker 1>Right.

248
00:11:28.000 --> 00:11:30.039
<v Speaker 2>It doesn't matter how many times you run it, what

249
00:11:30.120 --> 00:11:32.480
<v Speaker 2>time of day it is, or what other equations are

250
00:11:32.559 --> 00:11:35.519
<v Speaker 2>running next to it. A pure function will always yield

251
00:11:35.559 --> 00:11:39.240
<v Speaker 2>the exact same output for the same input, and crucially,

252
00:11:39.440 --> 00:11:41.120
<v Speaker 2>it has no secret side effects.

253
00:11:41.240 --> 00:11:45.159
<v Speaker 1>Side effects like secretly writing a log to a database,

254
00:11:45.600 --> 00:11:48.679
<v Speaker 1>or throwing an unhandled exception that crashes the program, or

255
00:11:48.799 --> 00:11:51.159
<v Speaker 1>changing some global variable exactly.

256
00:11:51.279 --> 00:11:53.919
<v Speaker 2>A pure function does nothing except take an input and

257
00:11:53.919 --> 00:11:54.879
<v Speaker 2>return an output.

258
00:11:54.960 --> 00:11:57.200
<v Speaker 1>And because there are no side effects, you get the

259
00:11:57.240 --> 00:12:01.200
<v Speaker 1>substitution model. You can mentally or programmatically just replace the

260
00:12:01.240 --> 00:12:02.639
<v Speaker 1>function call with its output. Right.

261
00:12:02.639 --> 00:12:04.399
<v Speaker 2>If I see square of three in the code, I

262
00:12:04.440 --> 00:12:08.440
<v Speaker 2>can literally substitute it with nine, making equational reasoning possible.

263
00:12:08.759 --> 00:12:10.519
<v Speaker 2>You can logically prove your code works.

264
00:12:10.720 --> 00:12:14.799
<v Speaker 1>The implication here is massive for building large architectures, because

265
00:12:14.840 --> 00:12:17.679
<v Speaker 1>if your functions are pure mathematical expressions, they give you

266
00:12:17.879 --> 00:12:22.360
<v Speaker 1>the ultimate superpower, which is compositionality. You can literally snap

267
00:12:22.559 --> 00:12:28.039
<v Speaker 1>small functions together to build larger behaviors like fusion exactly.

268
00:12:28.679 --> 00:12:31.039
<v Speaker 2>Say you need to map a list of accounts to

269
00:12:31.080 --> 00:12:33.480
<v Speaker 2>calculate their interest, and then map that list again to

270
00:12:33.519 --> 00:12:37.399
<v Speaker 2>deduct taxes. Okay, because those functions are pure, you can

271
00:12:37.480 --> 00:12:41.960
<v Speaker 2>algebraically fuse them together into a single pass. You calculate

272
00:12:42.000 --> 00:12:46.480
<v Speaker 2>the interest and deduct the tax simultaneously, which really optimizes performance.

273
00:12:46.519 --> 00:12:48.679
<v Speaker 1>Here's where it gets really interesting to me. Think of

274
00:12:48.720 --> 00:12:51.879
<v Speaker 1>compositionality like a massive plumbing system.

275
00:12:52.000 --> 00:12:52.759
<v Speaker 2>Okay, plumbing.

276
00:12:52.879 --> 00:12:55.159
<v Speaker 1>If you have a bunch of pure functions, they act

277
00:12:55.200 --> 00:12:58.480
<v Speaker 1>like different pieces of pipe. If the types align, like

278
00:12:58.519 --> 00:13:01.720
<v Speaker 1>if the pipe sizes matge exactly, you can snap these

279
00:13:01.720 --> 00:13:05.480
<v Speaker 1>functional pipes together to create a massive system without needing

280
00:13:05.519 --> 00:13:08.360
<v Speaker 1>to know anything about the actual water flowing inside them.

281
00:13:08.480 --> 00:13:09.159
<v Speaker 2>Oh that's good.

282
00:13:09.240 --> 00:13:12.639
<v Speaker 1>You define what you want to happen, and you completely abstract.

283
00:13:12.200 --> 00:13:15.039
<v Speaker 2>A way to how that analogy holds up perfectly. You

284
00:13:15.120 --> 00:13:19.519
<v Speaker 2>are assembling behaviors based purely on their algebraic contracts.

285
00:13:19.720 --> 00:13:23.399
<v Speaker 1>But pure math assumes a perfect world, a white room

286
00:13:23.440 --> 00:13:27.200
<v Speaker 1>where everything works perfectly. The real world is chaotic. Databases

287
00:13:27.240 --> 00:13:31.120
<v Speaker 1>get unplugged, hard drives get full, network connections drop out

288
00:13:31.159 --> 00:13:34.039
<v Speaker 1>in the middle of a transaction. How do we protect

289
00:13:34.120 --> 00:13:37.639
<v Speaker 1>our beautiful, pure algebra from the messy reality of the internet.

290
00:13:37.679 --> 00:13:39.159
<v Speaker 2>Well, this is where we bring in the third pillar,

291
00:13:39.200 --> 00:13:43.039
<v Speaker 2>which is reactive architecture. Pure logic is great, but software

292
00:13:43.120 --> 00:13:46.559
<v Speaker 2>has to actually survive the real world. A reactive model

293
00:13:46.600 --> 00:13:49.559
<v Speaker 2>relies on a specific three plus one view To achieve

294
00:13:49.559 --> 00:13:52.159
<v Speaker 2>this three plus one yeah. The ultimate goal is that

295
00:13:52.200 --> 00:13:55.039
<v Speaker 2>a system must be responsive.

296
00:13:54.720 --> 00:13:58.120
<v Speaker 1>Meaning bounded latency, like the user gets an answer quickly

297
00:13:58.279 --> 00:13:58.799
<v Speaker 1>no matter what.

298
00:13:59.039 --> 00:14:02.720
<v Speaker 2>Yes. But to guarantee responsiveness, it must be backed by

299
00:14:02.840 --> 00:14:06.879
<v Speaker 2>three interlocking treits. First, it must be resilient, meaning it

300
00:14:06.919 --> 00:14:08.440
<v Speaker 2>responds gracefully to failure.

301
00:14:08.559 --> 00:14:08.840
<v Speaker 1>Okay.

302
00:14:08.960 --> 00:14:11.639
<v Speaker 2>Second, it must be elastic, meaning it scales up and

303
00:14:11.679 --> 00:14:14.759
<v Speaker 2>down based on varying loads. And to achieve both resilience

304
00:14:14.799 --> 00:14:18.840
<v Speaker 2>and elasticity, the foundation must be message driven, relying on

305
00:14:18.879 --> 00:14:20.080
<v Speaker 2>asynchronous communication.

306
00:14:20.240 --> 00:14:23.320
<v Speaker 1>So we have to actively design for failure, which honestly

307
00:14:23.360 --> 00:14:25.720
<v Speaker 1>contradicts how a lot of legacy systems were built.

308
00:14:25.879 --> 00:14:28.559
<v Speaker 2>It does, but at scale, when you have ten thousand servers,

309
00:14:28.960 --> 00:14:32.360
<v Speaker 2>hardware will fail multiple times a day. It is a

310
00:14:32.399 --> 00:14:33.639
<v Speaker 2>mathematical certainty.

311
00:14:33.679 --> 00:14:34.559
<v Speaker 1>You just can't avoid it.

312
00:14:34.799 --> 00:14:38.320
<v Speaker 2>You don't pretend failures won't happen. You design the architects

313
00:14:38.360 --> 00:14:39.960
<v Speaker 2>are assuming they're happening right now.

314
00:14:40.120 --> 00:14:42.639
<v Speaker 1>But how does that work with our pure functional math,

315
00:14:42.840 --> 00:14:47.000
<v Speaker 1>Because in traditional code you see those messy tricatch blocks everywhere.

316
00:14:47.480 --> 00:14:49.679
<v Speaker 1>You know, try to write to the database. If it fails,

317
00:14:49.720 --> 00:14:53.279
<v Speaker 1>catch the error. But earlier you said throwing exceptions breaks

318
00:14:53.360 --> 00:14:57.120
<v Speaker 1>referential transparency. It's a secret side effect that basically ruins

319
00:14:57.159 --> 00:14:57.519
<v Speaker 1>the math.

320
00:14:57.679 --> 00:15:01.360
<v Speaker 2>It does. A tricatch block absolutely destroys the purity of

321
00:15:01.360 --> 00:15:04.080
<v Speaker 2>a function. The function is no longer just returning an

322
00:15:04.080 --> 00:15:07.360
<v Speaker 2>output based on an input. It's blowing up the execution stack.

323
00:15:08.039 --> 00:15:12.080
<v Speaker 2>So instead of mixing messy exception handling into our business logic,

324
00:15:12.480 --> 00:15:17.279
<v Speaker 2>functional programming meets reactive architecture by abstracting failures and latency

325
00:15:17.399 --> 00:15:21.039
<v Speaker 2>into actual data types. We call these monads monads.

326
00:15:21.120 --> 00:15:23.559
<v Speaker 1>Okay, how do they solve the trycatch problem?

327
00:15:23.600 --> 00:15:25.919
<v Speaker 2>Think of a monad as a special wrapper or a

328
00:15:25.960 --> 00:15:30.120
<v Speaker 2>shipping box. Instead of a function directly returning an account balance,

329
00:15:30.159 --> 00:15:33.519
<v Speaker 2>it returns a box called try, a box called try Yeah.

330
00:15:33.720 --> 00:15:36.960
<v Speaker 2>Inside that trybox is either the successful balance or the

331
00:15:37.039 --> 00:15:41.320
<v Speaker 2>failure exception. The function itself never crashes. It always safely

332
00:15:41.360 --> 00:15:42.200
<v Speaker 2>returns the box.

333
00:15:42.279 --> 00:15:44.639
<v Speaker 1>And if the network is just really slow, then.

334
00:15:44.679 --> 00:15:47.600
<v Speaker 2>We use a box called a future. It essentially says,

335
00:15:47.639 --> 00:15:49.320
<v Speaker 2>you know, I don't have the balance right now because

336
00:15:49.320 --> 00:15:51.600
<v Speaker 2>the network is slow, but here is a future box.

337
00:15:51.799 --> 00:15:54.000
<v Speaker 2>Keep executing the rest of the code, and I'll drop

338
00:15:54.039 --> 00:15:55.320
<v Speaker 2>the result in here when I'm done.

339
00:15:55.440 --> 00:15:58.559
<v Speaker 1>Oh wow, That allows the main thread of the application

340
00:15:58.840 --> 00:16:01.639
<v Speaker 1>to just keep moving. The user isn't staring at a

341
00:16:01.679 --> 00:16:05.000
<v Speaker 1>frozen screen because the main thread isn't blocked waiting for

342
00:16:05.039 --> 00:16:07.559
<v Speaker 1>a slow database exactly. But I do have a problem

343
00:16:07.600 --> 00:16:10.240
<v Speaker 1>with this. If we remove all that failure handling from

344
00:16:10.279 --> 00:16:13.639
<v Speaker 1>our pure business logic and we centralize it into a

345
00:16:13.679 --> 00:16:18.200
<v Speaker 1>separate failure handling module, doesn't that just create a massive bottleneck,

346
00:16:18.639 --> 00:16:21.879
<v Speaker 1>like you know, one traffic cop trying to manage all

347
00:16:21.919 --> 00:16:23.240
<v Speaker 1>the crashes for a whole city.

348
00:16:23.600 --> 00:16:26.799
<v Speaker 2>If you used a single global error handler, Yes, the

349
00:16:26.879 --> 00:16:28.519
<v Speaker 2>system would bottleneck immediately.

350
00:16:28.840 --> 00:16:30.240
<v Speaker 1>Okay, so how do they avoid it?

351
00:16:30.679 --> 00:16:34.399
<v Speaker 2>The reactive architecture avoids this by delegating those handlers based

352
00:16:34.399 --> 00:16:36.639
<v Speaker 2>on the specific bounded context we talked about.

353
00:16:36.480 --> 00:16:39.919
<v Speaker 1>Earlier, ah tying it back to the domain blueprint precisely.

354
00:16:40.200 --> 00:16:43.600
<v Speaker 2>The portfolio context has its handler, the transaction context has

355
00:16:43.639 --> 00:16:47.399
<v Speaker 2>its own. Treating exceptions and latency as manageable effects in

356
00:16:47.440 --> 00:16:51.639
<v Speaker 2>their own specific contexts allows our pure functional core to

357
00:16:51.720 --> 00:16:56.000
<v Speaker 2>scale elastically, so it's modular right. The system can spin

358
00:16:56.120 --> 00:16:59.039
<v Speaker 2>up more servers for just the specific context that is

359
00:16:59.080 --> 00:17:01.639
<v Speaker 2>struggling without bringing down the whole application.

360
00:17:02.120 --> 00:17:05.920
<v Speaker 1>To be truly asynchronous and message driven. Like you mentioned

361
00:17:05.920 --> 00:17:08.160
<v Speaker 1>in the three plus one view, it feels like we

362
00:17:08.240 --> 00:17:12.359
<v Speaker 1>have to rethink how our system fundamentally communicates. And I

363
00:17:12.400 --> 00:17:15.039
<v Speaker 1>see developers throw around the terms commands and events all

364
00:17:15.039 --> 00:17:17.960
<v Speaker 1>the time, almost interchangeable now all the time. But in

365
00:17:18.000 --> 00:17:19.880
<v Speaker 1>this architecture they aren't the same thing, are they.

366
00:17:20.079 --> 00:17:24.200
<v Speaker 2>They are drastically different, and understanding that difference is key

367
00:17:24.279 --> 00:17:27.480
<v Speaker 2>to a message driven system. A command is an instruction.

368
00:17:27.799 --> 00:17:30.960
<v Speaker 2>It is an imperative request like debit account, because it

369
00:17:31.039 --> 00:17:33.200
<v Speaker 2>is a request to change the state of the system

370
00:17:33.319 --> 00:17:36.359
<v Speaker 2>in the present or future. It can be rejected the

371
00:17:36.400 --> 00:17:39.519
<v Speaker 2>account might be empty. A command can fail in an event.

372
00:17:39.799 --> 00:17:43.920
<v Speaker 2>An event is a notification of a past change debit occurred.

373
00:17:44.359 --> 00:17:47.640
<v Speaker 2>It is a historical fact because it already happened. It

374
00:17:47.720 --> 00:17:50.400
<v Speaker 2>is completely immutable. You cannot reject.

375
00:17:50.119 --> 00:17:52.599
<v Speaker 1>History, so an event cannot fail exactly.

376
00:17:52.680 --> 00:17:54.359
<v Speaker 2>An event cannot fail, and.

377
00:17:54.359 --> 00:17:57.480
<v Speaker 1>This distinction leads us to one of the most powerful

378
00:17:57.599 --> 00:18:01.200
<v Speaker 1>concepts in modern system design, which is yes.

379
00:18:01.960 --> 00:18:05.440
<v Speaker 2>Think about how traditional databases work. They store the current state.

380
00:18:05.920 --> 00:18:07.880
<v Speaker 2>Let's look at the example of a customer named Bob

381
00:18:07.960 --> 00:18:11.119
<v Speaker 2>Okay Bob. In nineteen eighty nine, Bob opened an account

382
00:18:11.160 --> 00:18:13.920
<v Speaker 2>and lived at address A. In twenty ten, Bob moved

383
00:18:13.920 --> 00:18:17.319
<v Speaker 2>to address B. In a traditional database, you would execute

384
00:18:17.319 --> 00:18:20.640
<v Speaker 2>an update command and overwrite address A. With address B.

385
00:18:21.039 --> 00:18:24.039
<v Speaker 1>You literally erase the history to store the present you do.

386
00:18:24.359 --> 00:18:28.440
<v Speaker 2>But in an event source system, you don't overwrite anything ever. Instead,

387
00:18:28.559 --> 00:18:32.000
<v Speaker 2>the system logs a completely immutable event address.

388
00:18:31.680 --> 00:18:33.160
<v Speaker 1>Change, so it just adds it to a list.

389
00:18:33.400 --> 00:18:36.960
<v Speaker 2>Right, the database is no longer just a snapshot of

390
00:18:37.000 --> 00:18:41.039
<v Speaker 2>the current moment. It is a permanent, append only historical

391
00:18:41.119 --> 00:18:44.000
<v Speaker 2>log of every single thing that has ever happened in

392
00:18:44.000 --> 00:18:44.440
<v Speaker 2>the system.

393
00:18:44.519 --> 00:18:47.480
<v Speaker 1>Wait, if I want to know where Bob lives right now,

394
00:18:47.519 --> 00:18:50.160
<v Speaker 1>does the system have to read his entire forty year

395
00:18:50.240 --> 00:18:53.839
<v Speaker 1>life history just tofind his current zip code?

396
00:18:53.880 --> 00:18:56.799
<v Speaker 2>Theoretically yes. If you take the initial empty state of

397
00:18:56.799 --> 00:19:00.599
<v Speaker 2>the system at times zero and you mathematically apply every

398
00:19:00.640 --> 00:19:03.640
<v Speaker 2>single event in the log sequentially, you will arrive at

399
00:19:03.680 --> 00:19:05.400
<v Speaker 2>the exact current snapshot.

400
00:19:05.519 --> 00:19:06.160
<v Speaker 1>That's crazy.

401
00:19:06.200 --> 00:19:08.680
<v Speaker 2>The entire history of your business model boils down to

402
00:19:08.799 --> 00:19:11.319
<v Speaker 2>one long mathematical equation that.

403
00:19:11.279 --> 00:19:14.400
<v Speaker 1>Is essentially time travel. I mean, if a catastrophic bug

404
00:19:14.640 --> 00:19:17.519
<v Speaker 1>corrupts the current state of the database, you don't panic.

405
00:19:17.680 --> 00:19:20.240
<v Speaker 1>You just wipe the corrupted current state, go back to

406
00:19:20.279 --> 00:19:22.440
<v Speaker 1>the event log, and replay the math right up to

407
00:19:22.480 --> 00:19:23.640
<v Speaker 1>the second before the bug hit.

408
00:19:23.759 --> 00:19:27.599
<v Speaker 2>It makes the system incredibly resilient, and practically systems take

409
00:19:27.680 --> 00:19:30.319
<v Speaker 2>periodic snapshots so they don't have to read forty years

410
00:19:30.359 --> 00:19:32.440
<v Speaker 2>of history every single time you log in. Oh, that

411
00:19:32.440 --> 00:19:35.400
<v Speaker 2>makes sense, but the ultimate source of truth is always

412
00:19:35.440 --> 00:19:39.400
<v Speaker 2>that event log. It completely aligns with the functional programming

413
00:19:39.480 --> 00:19:43.400
<v Speaker 2>ideal of immutable data. You never mutate the past, you

414
00:19:43.559 --> 00:19:45.640
<v Speaker 2>only append new facts to the log.

415
00:19:45.759 --> 00:19:48.160
<v Speaker 1>Let's step back and synthesize all this. Yeah, because we

416
00:19:48.200 --> 00:19:51.039
<v Speaker 1>have covered some serious architectural ground today, we really have.

417
00:19:51.680 --> 00:19:54.640
<v Speaker 1>What we have learned from diving into this domain modeling

418
00:19:54.680 --> 00:19:59.359
<v Speaker 1>approach is that functional programming gives us predictability and the

419
00:19:59.440 --> 00:20:03.799
<v Speaker 1>safety pure mathematical logic. But pure logic isn't enough on

420
00:20:03.839 --> 00:20:08.079
<v Speaker 1>its own. Reactive programming takes that pure logic and gives

421
00:20:08.079 --> 00:20:12.480
<v Speaker 1>it a shield to survive the real world, keeping it responsive, elastic,

422
00:20:12.559 --> 00:20:15.640
<v Speaker 1>and resilient to failure by passing around boxes like try

423
00:20:15.720 --> 00:20:17.039
<v Speaker 1>and future instead of.

424
00:20:17.000 --> 00:20:19.960
<v Speaker 2>Crashing, and by wrapping all of that within domain driven design,

425
00:20:20.480 --> 00:20:23.079
<v Speaker 2>using the ubiquitous language of the business, you end up

426
00:20:23.079 --> 00:20:26.039
<v Speaker 2>with software that accurately reflects the real world and can

427
00:20:26.079 --> 00:20:28.599
<v Speaker 2>scale globally without collapsing under its own weight.

428
00:20:28.720 --> 00:20:30.400
<v Speaker 1>So what does this all mean for us, the people

429
00:20:30.440 --> 00:20:32.240
<v Speaker 1>actually using these systems? I want to leave you with

430
00:20:32.240 --> 00:20:34.440
<v Speaker 1>a final concept to mull over on your own.

431
00:20:34.680 --> 00:20:35.200
<v Speaker 2>Go for it.

432
00:20:35.400 --> 00:20:38.400
<v Speaker 1>We just talked about event sourcing. If the most resilient

433
00:20:38.799 --> 00:20:42.039
<v Speaker 1>modern software is shifting away from just storing our current

434
00:20:42.079 --> 00:20:46.559
<v Speaker 1>status and instead is moving toward building an immutable, permanent

435
00:20:46.680 --> 00:20:49.799
<v Speaker 1>log of every single event and action we have ever taken,

436
00:20:50.440 --> 00:20:53.160
<v Speaker 1>how does an architecture that is designed to remember everything

437
00:20:53.240 --> 00:20:57.319
<v Speaker 1>forever impact our digital privacy and basically the human right

438
00:20:57.359 --> 00:20:58.640
<v Speaker 1>to be forgotten? Wow?

439
00:20:59.519 --> 00:21:00.599
<v Speaker 2>That is a heavy thought.

440
00:21:01.079 --> 00:21:03.359
<v Speaker 1>It's something to think about the next time you update

441
00:21:03.359 --> 00:21:06.160
<v Speaker 1>your address online, or the next time you are sitting

442
00:21:06.200 --> 00:21:08.920
<v Speaker 1>on a retail site on Black Friday and the cart

443
00:21:08.960 --> 00:21:12.839
<v Speaker 1>actually works perfectly processing your order instantly. You'll know it's not.

444
00:21:12.880 --> 00:21:15.559
<v Speaker 2>Magic, it's just really really good math exactly.

445
00:21:15.920 --> 00:21:17.799
<v Speaker 1>Thank you for joining us on this deep dive. We'll

446
00:21:17.839 --> 00:21:18.680
<v Speaker 1>catch you on the next one.
