WEBVTT

1
00:00:00.160 --> 00:00:02.759
<v Speaker 1>Welcome to the Deep Dive, the show where we sift

2
00:00:02.799 --> 00:00:05.799
<v Speaker 1>through the noise, snack up the sources, and extract the

3
00:00:05.839 --> 00:00:09.759
<v Speaker 1>most potent nuggets of wisdom just for you. You know,

4
00:00:09.800 --> 00:00:12.279
<v Speaker 1>if you've ever tried to create something, especially software, you

5
00:00:12.320 --> 00:00:15.160
<v Speaker 1>get that drive, right, that feeling of building something meaningful.

6
00:00:15.279 --> 00:00:18.920
<v Speaker 1>But then sometimes that joy kind of fades, doesn't it,

7
00:00:19.199 --> 00:00:22.359
<v Speaker 1>When the cost, the sheer effort of changing or maintaining

8
00:00:22.399 --> 00:00:24.199
<v Speaker 1>it just seems to outweigh the value.

9
00:00:24.399 --> 00:00:27.440
<v Speaker 2>Oh, absolutely is a path. Pretty much everyone in software walks.

10
00:00:27.559 --> 00:00:30.000
<v Speaker 2>You're excited, you ship something, it works, Yeah, But then

11
00:00:30.039 --> 00:00:32.119
<v Speaker 2>comes the long game. How does it live? How does

12
00:00:32.159 --> 00:00:35.119
<v Speaker 2>it adapt? That's where the real challenge often kicks in,

13
00:00:35.200 --> 00:00:35.759
<v Speaker 2>sometimes the.

14
00:00:35.719 --> 00:00:40.240
<v Speaker 1>Pain too exactly, And that challenge that's precisely why today

15
00:00:40.280 --> 00:00:44.359
<v Speaker 1>we're doing a deep dive into object oriented design ODE.

16
00:00:44.759 --> 00:00:48.320
<v Speaker 1>We're leaning heavily on a fantastic book, Practical Object Oriented

17
00:00:48.320 --> 00:00:52.200
<v Speaker 1>Design and Agile Primer Using Ruby by Sandy Mets. But

18
00:00:52.719 --> 00:00:55.039
<v Speaker 1>let's be clear, this isn't really about learning to code,

19
00:00:55.439 --> 00:00:58.000
<v Speaker 1>specifically Ruby or anything. Our mission here is more like

20
00:00:58.000 --> 00:01:01.640
<v Speaker 1>a shortcut, a shortcut to understand how to arrange code

21
00:01:01.679 --> 00:01:05.000
<v Speaker 1>well so your software stays joyful to work on productive

22
00:01:05.079 --> 00:01:08.480
<v Speaker 1>and it can actually handle future changes gracefully. It's about

23
00:01:08.519 --> 00:01:11.920
<v Speaker 1>getting really clued into those design principles that make working

24
00:01:11.959 --> 00:01:13.920
<v Speaker 1>on software a pleasure not a chore.

25
00:01:14.920 --> 00:01:18.079
<v Speaker 2>And it all starts really with one fundamental truth about

26
00:01:18.079 --> 00:01:20.560
<v Speaker 2>software dot change, it just happens. Yeah, you can imagine

27
00:01:20.560 --> 00:01:23.359
<v Speaker 2>this like fantasy world where software is written once requirements

28
00:01:23.400 --> 00:01:24.400
<v Speaker 2>are perfect, never changed.

29
00:01:24.439 --> 00:01:27.200
<v Speaker 1>Oh wouldn't that be nice? No bugs, no new features needed,

30
00:01:27.359 --> 00:01:29.959
<v Speaker 1>just done forever exactly.

31
00:01:30.000 --> 00:01:33.280
<v Speaker 2>And in that world, honestly, design wouldn't matter that much.

32
00:01:33.319 --> 00:01:34.959
<v Speaker 2>Your code could be a mess, but who cares, It

33
00:01:35.040 --> 00:01:39.079
<v Speaker 2>just runs. But reality, well, as Sandimes puts it so well,

34
00:01:39.239 --> 00:01:43.599
<v Speaker 2>change is unavoidable. It is ubiquitous, omnipresent, and inevitable. It's

35
00:01:43.760 --> 00:01:44.799
<v Speaker 2>just the water we swim in.

36
00:01:44.879 --> 00:01:47.640
<v Speaker 1>Okay, So if change is truly that inevitable, what's like

37
00:01:48.280 --> 00:01:51.280
<v Speaker 1>the most counterintuitive thing a developer should maybe start doing

38
00:01:51.280 --> 00:01:54.079
<v Speaker 1>differently right now, something that isn't immediately obvious.

39
00:01:54.439 --> 00:01:58.400
<v Speaker 2>That's a good one. I'd say the most counterintuitive shift

40
00:01:58.480 --> 00:02:01.519
<v Speaker 2>is probably aiming for FlexIt ability or trying to get

41
00:02:01.519 --> 00:02:05.280
<v Speaker 2>it perfect on day one. So many devs they want

42
00:02:05.280 --> 00:02:08.919
<v Speaker 2>the ideal solution immediately, trying to guess every future need

43
00:02:09.360 --> 00:02:12.439
<v Speaker 2>but if change is guaranteed, your perfect first guess is

44
00:02:12.479 --> 00:02:16.280
<v Speaker 2>almost certainly wrong or at least incomplete. So instead you

45
00:02:16.319 --> 00:02:19.919
<v Speaker 2>should focus on making the code easy to change, even

46
00:02:19.960 --> 00:02:24.400
<v Speaker 2>if that means putting off some decisions like unmanaged dependencies.

47
00:02:24.439 --> 00:02:27.039
<v Speaker 2>They are the real killers here, often silent ones. They're

48
00:02:27.080 --> 00:02:30.560
<v Speaker 2>like these invisible strings tying bits of code together. If

49
00:02:30.560 --> 00:02:33.240
<v Speaker 2>you don't manage them carefully, even a tiny tweak, well,

50
00:02:33.280 --> 00:02:36.520
<v Speaker 2>the damage can just radiate outward and overlapping concentric circles.

51
00:02:37.000 --> 00:02:40.039
<v Speaker 2>Suddenly nothing feels safe to touch. You start with something

52
00:02:40.039 --> 00:02:42.919
<v Speaker 2>small and successful, and before you know it, it's a tarpit.

53
00:02:43.520 --> 00:02:45.080
<v Speaker 2>Every step feels dangerous.

54
00:02:44.800 --> 00:02:46.560
<v Speaker 1>Right the tar pit. And that's where the books says

55
00:02:46.560 --> 00:02:49.520
<v Speaker 1>something really interesting. Design is thus an art, the art

56
00:02:49.560 --> 00:02:52.800
<v Speaker 1>of arranging code. It's not just about making it work now.

57
00:02:52.840 --> 00:02:56.319
<v Speaker 1>It's about setting it up so it's understandable and changeable.

58
00:02:55.879 --> 00:02:59.439
<v Speaker 2>Later, precisely. And we have tools for this art right

59
00:03:00.000 --> 00:03:04.199
<v Speaker 2>design principles, design patterns, These are our guides. Academics have

60
00:03:04.240 --> 00:03:07.439
<v Speaker 2>even tried to measure this stuff. You quantify goodness. There

61
00:03:07.439 --> 00:03:11.319
<v Speaker 2>are metrics from to Damburn camera. Back in the day,

62
00:03:11.319 --> 00:03:13.719
<v Speaker 2>they looked at things like how many connections does the

63
00:03:13.759 --> 00:03:17.039
<v Speaker 2>class have how complex are its methods? And they did

64
00:03:17.120 --> 00:03:20.439
<v Speaker 2>find correlations between using these kinds of design techniques and

65
00:03:20.560 --> 00:03:23.639
<v Speaker 2>ending up with higher quality code. But it's important to

66
00:03:23.680 --> 00:03:27.919
<v Speaker 2>remember bad ode metrics are indisputably a sign of bad design.

67
00:03:28.879 --> 00:03:32.120
<v Speaker 2>If your metrics look bad, your code's probably hard to change.

68
00:03:32.560 --> 00:03:36.000
<v Speaker 1>But getting good scores doesn't automatically mean your design is great.

69
00:03:36.199 --> 00:03:39.520
<v Speaker 2>Does it exactly right? Good scores don't prove the opposite.

70
00:03:39.960 --> 00:03:43.479
<v Speaker 2>You could definitely over anticipate the future. You might build

71
00:03:43.479 --> 00:03:46.759
<v Speaker 2>this elegant structure that anticipates all the wrong changes. Then

72
00:03:46.759 --> 00:03:49.919
<v Speaker 2>when the real future shows up, it's actually expensive to adapt,

73
00:03:50.599 --> 00:03:53.800
<v Speaker 2>which brings us to technical debt. It's like borrowing time

74
00:03:53.840 --> 00:03:56.599
<v Speaker 2>from the future. You take a short cut now, but

75
00:03:56.680 --> 00:03:58.599
<v Speaker 2>you know you'll have to pay it back later, probably

76
00:03:58.680 --> 00:04:01.080
<v Speaker 2>with interest. Sometimes it's a bunch's choice, but you have

77
00:04:01.120 --> 00:04:02.000
<v Speaker 2>to plan to repay.

78
00:04:02.080 --> 00:04:04.879
<v Speaker 1>That's a really useful way to think about it. So, yeah, okay,

79
00:04:04.919 --> 00:04:07.599
<v Speaker 1>design can fail. What does it look like when there's

80
00:04:07.680 --> 00:04:11.199
<v Speaker 1>just no design you just code? It works for a bit.

81
00:04:11.319 --> 00:04:14.159
<v Speaker 2>Yeah, that leads to code that's easy to write but

82
00:04:14.319 --> 00:04:19.439
<v Speaker 2>gradually impossible to change. Your programmers start saying things like yeah,

83
00:04:19.439 --> 00:04:21.800
<v Speaker 2>I can add that, but honestly, it's going to break everything.

84
00:04:22.439 --> 00:04:23.160
<v Speaker 2>That's a bad sign.

85
00:04:23.199 --> 00:04:26.040
<v Speaker 1>Okay, so that's one extreme. What about the other overdesign?

86
00:04:26.600 --> 00:04:32.839
<v Speaker 2>Ah? Yes, the complicated, beautiful castles of code. They look amazing, architecturally.

87
00:04:32.199 --> 00:04:34.040
<v Speaker 1>Sound, but totally inflexible.

88
00:04:34.120 --> 00:04:36.959
<v Speaker 2>Exactly, they're hemmed in by stone walls. Now, the response

89
00:04:37.000 --> 00:04:39.079
<v Speaker 2>to a new feature is no, I can't add that feature.

90
00:04:39.120 --> 00:04:40.160
<v Speaker 2>It wasn't designed to do that.

91
00:04:40.480 --> 00:04:42.879
<v Speaker 1>So no design is bad. Over design is bad. What

92
00:04:43.000 --> 00:04:45.600
<v Speaker 1>about trying to do all the design first, that whole

93
00:04:45.680 --> 00:04:48.839
<v Speaker 1>big upfront design thing, but you have to separate the

94
00:04:48.839 --> 00:04:50.000
<v Speaker 1>designers from the coders.

95
00:04:50.199 --> 00:04:53.720
<v Speaker 2>Yeah, that often creates this weird tension, you know, designers

96
00:04:53.759 --> 00:04:57.600
<v Speaker 2>versus programmers and the design itself. It's almost always wrong

97
00:04:57.720 --> 00:05:01.160
<v Speaker 2>in some way because as the books as, certainty is

98
00:05:01.199 --> 00:05:04.199
<v Speaker 2>unattainable in advance of the application's existence. You just can't

99
00:05:04.240 --> 00:05:06.839
<v Speaker 2>know everything upfront. And this is where agile comes in.

100
00:05:07.079 --> 00:05:10.439
<v Speaker 2>People sometimes think agile means no design, but that's wrong.

101
00:05:11.079 --> 00:05:13.839
<v Speaker 2>Agile does not prohibit design. It requires it. In fact,

102
00:05:13.879 --> 00:05:17.439
<v Speaker 2>it requires really good design. Design that's simple, flexible, ready

103
00:05:17.480 --> 00:05:19.439
<v Speaker 2>for change because change is the constant.

104
00:05:20.319 --> 00:05:23.040
<v Speaker 1>Okay, so if good design is about arranging code to

105
00:05:23.079 --> 00:05:26.680
<v Speaker 1>handle change, let's dig into object oriented programming itself. How

106
00:05:26.680 --> 00:05:29.639
<v Speaker 1>does OP help with this flexibility compared to older ways.

107
00:05:29.839 --> 00:05:33.560
<v Speaker 2>Well, think about older procedural languages. You generally had your

108
00:05:33.600 --> 00:05:36.160
<v Speaker 2>data structures over here and your functions that operate on

109
00:05:36.160 --> 00:05:39.839
<v Speaker 2>that data over there, separate things. OO languages like Ruby,

110
00:05:39.879 --> 00:05:42.480
<v Speaker 2>which the book uses, they combine them together into a

111
00:05:42.519 --> 00:05:43.800
<v Speaker 2>single thing, an object.

112
00:05:44.800 --> 00:05:45.000
<v Speaker 1>Hah.

113
00:05:45.519 --> 00:05:48.439
<v Speaker 2>So now you're not thinking about data and action separately.

114
00:05:48.800 --> 00:05:51.040
<v Speaker 2>You're thinking about things objects that no stuff and do

115
00:05:51.199 --> 00:05:54.759
<v Speaker 2>stuff all bundled together. It changes how you model the problem.

116
00:05:55.000 --> 00:05:57.680
<v Speaker 2>And Ruby, for instance, is open ended, you can invent

117
00:05:57.800 --> 00:06:00.639
<v Speaker 2>brand new types of your own. What happens is your

118
00:06:00.639 --> 00:06:04.639
<v Speaker 2>application sort of evolves into its own unique programming language

119
00:06:04.800 --> 00:06:07.839
<v Speaker 2>that is specifically tailored to your domain. You could express

120
00:06:07.879 --> 00:06:10.120
<v Speaker 2>ideas about your problem really naturally.

121
00:06:09.720 --> 00:06:12.439
<v Speaker 1>Building your own language. That's a cool perspective. Okay, let's

122
00:06:12.439 --> 00:06:15.519
<v Speaker 1>get practical. What are the core OD principles that help

123
00:06:15.600 --> 00:06:18.560
<v Speaker 1>us build these flexible systems? Starting with big one Single

124
00:06:18.600 --> 00:06:20.399
<v Speaker 1>responsibility principle SRP.

125
00:06:20.800 --> 00:06:25.199
<v Speaker 2>Right SRP. The core idea sounds simple. A class should

126
00:06:25.199 --> 00:06:28.040
<v Speaker 2>do the smallest possible useful thing. It should have a

127
00:06:28.079 --> 00:06:31.199
<v Speaker 2>single responsibility. If a class is juggling too many jobs,

128
00:06:31.199 --> 00:06:34.399
<v Speaker 2>It gets hard to reuse, things get tangled up. Changes

129
00:06:34.439 --> 00:06:37.560
<v Speaker 2>in one responsibility break others. Yeah, it's a mess.

130
00:06:37.639 --> 00:06:41.759
<v Speaker 1>Single responsibility sounds easy, But how do you actually know

131
00:06:41.839 --> 00:06:44.120
<v Speaker 1>if a class is doing too much? Is there a

132
00:06:44.120 --> 00:06:44.959
<v Speaker 1>practical test?

133
00:06:45.120 --> 00:06:48.879
<v Speaker 2>Yeah, there's a neat trick. The book suggests you interrogate it.

134
00:06:48.959 --> 00:06:51.879
<v Speaker 2>You try phrasing its methods as questions directed to the class.

135
00:06:51.879 --> 00:06:55.120
<v Speaker 2>So please, mister gear, what is your ratio? That sounds

136
00:06:55.120 --> 00:06:58.600
<v Speaker 2>totally normal. Gear should know its ratio. But please, mister gear,

137
00:06:58.600 --> 00:07:01.199
<v Speaker 2>what is your tire size? That just sounds wrong? Doesn't it?

138
00:07:01.240 --> 00:07:03.480
<v Speaker 2>A gear doesn't have a tire. If the question feels

139
00:07:03.480 --> 00:07:06.439
<v Speaker 2>awkward or nonsensical, the class is probably doing things it

140
00:07:06.439 --> 00:07:09.720
<v Speaker 2>shouldn't be. It has too many responsibilities, and this ties

141
00:07:09.720 --> 00:07:12.040
<v Speaker 2>into asking yourself, what is the future cost of doing

142
00:07:12.040 --> 00:07:15.040
<v Speaker 2>nothing today? Sometimes the best move is to not make

143
00:07:15.079 --> 00:07:17.879
<v Speaker 2>a big design decision yet, wait until you know more.

144
00:07:18.199 --> 00:07:19.639
<v Speaker 2>Making a class too early.

145
00:07:19.560 --> 00:07:23.040
<v Speaker 1>Is just guessing, and this idea single responsibility. It applies

146
00:07:23.079 --> 00:07:24.680
<v Speaker 1>to methods too, not just classes.

147
00:07:24.959 --> 00:07:29.040
<v Speaker 2>Oh, absolutely, methods should also do one thing well. Keeping

148
00:07:29.079 --> 00:07:32.680
<v Speaker 2>methods small and focused has huge benefits. It makes the

149
00:07:32.720 --> 00:07:35.839
<v Speaker 2>code clearer, often eliminates the need for comments Because the

150
00:07:35.839 --> 00:07:39.839
<v Speaker 2>method name says it all. It encourages reuse. Plus, small

151
00:07:39.879 --> 00:07:42.360
<v Speaker 2>focus methods are much easier to move to a different

152
00:07:42.360 --> 00:07:46.040
<v Speaker 2>class if you realize later that the responsibility belongs elsewhere.

153
00:07:46.360 --> 00:07:49.439
<v Speaker 2>Sometimes you might even start by putting a small related

154
00:07:49.480 --> 00:07:53.680
<v Speaker 2>responsibility inside a temporary structure like a structin Ruby, within

155
00:07:53.720 --> 00:07:56.759
<v Speaker 2>the main class. It's like a holding pattern before deciding

156
00:07:56.759 --> 00:07:58.240
<v Speaker 2>if it needs its own full class.

157
00:07:58.480 --> 00:08:02.120
<v Speaker 1>Okay, so keep things focused, single responsibility. But these focused

158
00:08:02.160 --> 00:08:05.199
<v Speaker 1>things need to work together, which brings us to dependencies

159
00:08:05.639 --> 00:08:08.360
<v Speaker 1>the glue. The book calls it a little dot of blue,

160
00:08:08.399 --> 00:08:11.319
<v Speaker 1>but warns that too much can strangle your application. How

161
00:08:11.319 --> 00:08:12.439
<v Speaker 1>do we manage that glue?

162
00:08:12.480 --> 00:08:15.759
<v Speaker 2>Managing dependencies is maybe the central challenge, and a key

163
00:08:15.800 --> 00:08:20.560
<v Speaker 2>technique is dependency injection. Sounds fancy, but the idea is simple.

164
00:08:20.839 --> 00:08:23.800
<v Speaker 2>Instead of an object creating its own collaborators, like Gear

165
00:08:23.839 --> 00:08:26.360
<v Speaker 2>making its own wheel, you pass the collaborator in from

166
00:08:26.360 --> 00:08:29.160
<v Speaker 2>the outside, so Gear just gets given a real object

167
00:08:29.160 --> 00:08:32.840
<v Speaker 2>when it's created. The result, Gear actually becomes smarter because

168
00:08:32.879 --> 00:08:35.039
<v Speaker 2>it knows less. It doesn't need to know how to

169
00:08:35.080 --> 00:08:37.120
<v Speaker 2>create a wheel, or even that it is a wheel.

170
00:08:37.679 --> 00:08:40.120
<v Speaker 2>All Gear cares about is that the object it receives

171
00:08:40.279 --> 00:08:43.480
<v Speaker 2>responds to the messages it needs, like diameter. That's it

172
00:08:43.960 --> 00:08:46.000
<v Speaker 2>immensely powerful for flexibility.

173
00:08:46.399 --> 00:08:49.200
<v Speaker 1>That makes a lot of sense Practically speaking, how often

174
00:08:49.200 --> 00:08:51.919
<v Speaker 1>do you find yourself using dependency injection? What's the biggest

175
00:08:51.919 --> 00:08:52.960
<v Speaker 1>win you see from it?

176
00:08:52.960 --> 00:08:55.279
<v Speaker 2>It becomes second nature. Really, you're constantly thinking, does this

177
00:08:55.360 --> 00:08:57.600
<v Speaker 2>object really need to know how to create that other object?

178
00:08:58.039 --> 00:09:00.919
<v Speaker 2>Usually the answer is no, So in jen acting dependencies,

179
00:09:01.039 --> 00:09:04.240
<v Speaker 2>especially through the constructor, becomes standard practice. The biggest win,

180
00:09:04.759 --> 00:09:08.480
<v Speaker 2>hands down, it's testability and substitutability. You can easily swap

181
00:09:08.519 --> 00:09:10.720
<v Speaker 2>at a fake test wheel when testing gear, or a

182
00:09:10.720 --> 00:09:13.440
<v Speaker 2>completely different kind of wheel later without changing gear at all,

183
00:09:13.519 --> 00:09:16.480
<v Speaker 2>as long as it provides that diameter method and related tip,

184
00:09:16.519 --> 00:09:20.320
<v Speaker 2>the book mentions using keyword arguments for initialization instead of

185
00:09:20.320 --> 00:09:23.120
<v Speaker 2>relying on the order of arguments. You name them year

186
00:09:23.159 --> 00:09:26.759
<v Speaker 2>dot new chane ring five bay good fifty two, cog

187
00:09:26.919 --> 00:09:30.399
<v Speaker 2>eleven wheel dot mywheel. This makes the code much clearer

188
00:09:30.399 --> 00:09:32.919
<v Speaker 2>and less brittle. If you add or change arguments later,

189
00:09:33.120 --> 00:09:36.200
<v Speaker 2>no more remembering was chain ring first or second? Stepping back,

190
00:09:36.240 --> 00:09:38.639
<v Speaker 2>the big idea here is depend on things that change

191
00:09:38.720 --> 00:09:42.799
<v Speaker 2>less often than you do. Concrete classes, specific implementations, they

192
00:09:42.840 --> 00:09:47.120
<v Speaker 2>tend to change. Abstract interfaces these common stable qualities they

193
00:09:47.200 --> 00:09:49.799
<v Speaker 2>change much less often. So you want your pendencies pointing

194
00:09:49.799 --> 00:09:51.840
<v Speaker 2>towards abstractions, not concrete details.

195
00:09:52.039 --> 00:09:58.039
<v Speaker 1>Okay, focus responsibilities, manage dependencies, But how do these objects

196
00:09:58.120 --> 00:10:01.720
<v Speaker 1>actually communicate effectively? How do we design those conversations well?

197
00:10:01.720 --> 00:10:06.440
<v Speaker 2>Fundamentally, an object oriented application is defined by messages being

198
00:10:06.480 --> 00:10:09.960
<v Speaker 2>sent between objects. The book uses a great analogy a

199
00:10:10.000 --> 00:10:14.480
<v Speaker 2>restaurant kitchen. The menu is the public interface. Customers order

200
00:10:14.519 --> 00:10:16.960
<v Speaker 2>off the menu. They don't need to know the complex

201
00:10:17.039 --> 00:10:20.159
<v Speaker 2>process happening inside the kitchen. That's private. Your classes should

202
00:10:20.159 --> 00:10:23.000
<v Speaker 2>be the same. A clear public interface, the menu of

203
00:10:23.080 --> 00:10:26.159
<v Speaker 2>methods others can call and private internal.

204
00:10:25.840 --> 00:10:29.120
<v Speaker 1>Workings and sequence diagrams come in handy here. The book

205
00:10:29.120 --> 00:10:32.360
<v Speaker 1>calls them a perfect low cost way to experiment. It

206
00:10:32.480 --> 00:10:35.559
<v Speaker 1>shifts thinking from what does this class do to who

207
00:10:35.600 --> 00:10:37.639
<v Speaker 1>responds to this message exactly?

208
00:10:37.759 --> 00:10:40.240
<v Speaker 2>That shift is crucial because, as Met says, you don't

209
00:10:40.279 --> 00:10:42.600
<v Speaker 2>send messages because you have objects. You have objects because

210
00:10:42.639 --> 00:10:45.919
<v Speaker 2>you send messages. Thinking about the messages first helps you

211
00:10:45.960 --> 00:10:48.919
<v Speaker 2>discover the objects you actually need and what their public

212
00:10:48.960 --> 00:10:50.039
<v Speaker 2>interfaces should.

213
00:10:49.759 --> 00:10:52.519
<v Speaker 1>Be, which leads to another key idea, asking for what

214
00:10:52.759 --> 00:10:55.720
<v Speaker 1>instead of telling how Take the example.

215
00:10:55.399 --> 00:10:57.960
<v Speaker 2>Of a trip class and a mechanic object. Instead of

216
00:10:57.960 --> 00:11:00.639
<v Speaker 2>trip telling mechanic every single step, check breaks and flight

217
00:11:00.720 --> 00:11:03.600
<v Speaker 2>tires Lubrik chain the trips. You just ask the mechanic

218
00:11:03.679 --> 00:11:06.679
<v Speaker 2>to do the what prepare trip and trust the mechanic

219
00:11:06.759 --> 00:11:08.919
<v Speaker 2>to know how to do that. This is blind trust

220
00:11:09.000 --> 00:11:12.279
<v Speaker 2>in ode. Objects collaborate by relying on each other's public

221
00:11:12.320 --> 00:11:16.200
<v Speaker 2>interfaces without needing intimate knowledge of the internal details. It

222
00:11:16.279 --> 00:11:17.440
<v Speaker 2>keeps them loosely coupled.

223
00:11:17.679 --> 00:11:21.320
<v Speaker 1>And what about controlling access? Ruby has public protected private?

224
00:11:21.360 --> 00:11:22.559
<v Speaker 1>Are these strict walls?

225
00:11:22.840 --> 00:11:25.200
<v Speaker 2>Not really? You know, the book calls them flexible barriers

226
00:11:25.519 --> 00:11:28.679
<v Speaker 2>in Ruby, and like some other languages, these aren't absolute guarantees.

227
00:11:29.279 --> 00:11:33.279
<v Speaker 2>Because of that, many experienced rubyists actually prefer using comments

228
00:11:33.360 --> 00:11:36.360
<v Speaker 2>or naming conventions like starting private method names with an

229
00:11:36.440 --> 00:11:39.759
<v Speaker 2>underscore to signal intent, rather than relying solely on the

230
00:11:39.799 --> 00:11:43.399
<v Speaker 2>key words. It's more about convention and trusting other developers.

231
00:11:44.000 --> 00:11:48.279
<v Speaker 1>Okay, so flexible barriers. This sounds related to minimizing dependencies. Again.

232
00:11:48.799 --> 00:11:53.279
<v Speaker 1>Are there common ways people mess up object communication anti patterns?

233
00:11:53.480 --> 00:11:56.039
<v Speaker 2>Oh? Definitely. A classic one is violating the law of demeter.

234
00:11:56.399 --> 00:11:59.000
<v Speaker 2>The simple version is only talk to your immediate neighbors,

235
00:11:59.080 --> 00:12:02.519
<v Speaker 2>or even simpler, use only one dot. You see code

236
00:12:02.639 --> 00:12:06.000
<v Speaker 2>like customer dot, bicycle, dot wheel, dot rotate. That's often

237
00:12:06.000 --> 00:12:06.840
<v Speaker 2>called a train wreck.

238
00:12:07.000 --> 00:12:09.200
<v Speaker 1>A train wreck, okay, why is that so bad?

239
00:12:09.399 --> 00:12:12.279
<v Speaker 2>Because it deeply couples the code calling rotate to the

240
00:12:12.440 --> 00:12:17.240
<v Speaker 2>entire internal structure of customer, bicycle and wheel. If any

241
00:12:17.240 --> 00:12:20.480
<v Speaker 2>part of that chain changes, maybe bicycle no longer directly

242
00:12:20.519 --> 00:12:23.440
<v Speaker 2>holds a wheel, this code breaks even though just wanted

243
00:12:23.440 --> 00:12:28.080
<v Speaker 2>to rotate something. These chains are not transparent, reasonable, usable,

244
00:12:28.159 --> 00:12:31.600
<v Speaker 2>or exemplary. They hide dependencies and make the code fragile.

245
00:12:32.000 --> 00:12:34.080
<v Speaker 2>When you find yourself writing code like that, it's a

246
00:12:34.080 --> 00:12:37.120
<v Speaker 2>strong signal. Listening to demeter tells you where your public

247
00:12:37.159 --> 00:12:40.519
<v Speaker 2>interfaces are lacking. You probably need a method on bicycle

248
00:12:40.559 --> 00:12:43.399
<v Speaker 2>itself like rotate wheel to hide that internal chain.

249
00:12:43.559 --> 00:12:46.840
<v Speaker 1>That makes sense. It forces better interface design. Okay, let's

250
00:12:46.840 --> 00:12:49.919
<v Speaker 1>shift gears to structuring behavior. How can we use dynamic

251
00:12:49.960 --> 00:12:52.360
<v Speaker 1>behavior like duct typing to keep costs down?

252
00:12:52.559 --> 00:12:55.600
<v Speaker 2>Right? Duck typing. The core idea is it's not what

253
00:12:55.679 --> 00:12:59.120
<v Speaker 2>an object is that matters, it's what it does. If

254
00:12:59.120 --> 00:13:01.639
<v Speaker 2>an object walks like a duck and quacks like a duck,

255
00:13:01.879 --> 00:13:04.000
<v Speaker 2>than for the purpose of the code interacting with it.

256
00:13:04.240 --> 00:13:06.320
<v Speaker 2>You can treat it as a duck. You care about

257
00:13:06.320 --> 00:13:09.759
<v Speaker 2>its behavior. It's public interface, not its specific class name.

258
00:13:10.320 --> 00:13:13.039
<v Speaker 2>The book uses a funny metaphor. An object is like

259
00:13:13.080 --> 00:13:16.519
<v Speaker 2>a partygoer at a masquerade ball that changes masks. Its

260
00:13:16.600 --> 00:13:19.600
<v Speaker 2>role can change depending on the context. A big warning

261
00:13:19.639 --> 00:13:22.200
<v Speaker 2>sign the book points out is seeing a case statement

262
00:13:22.240 --> 00:13:25.799
<v Speaker 2>that switches based on class names like caseobject dot class,

263
00:13:26.000 --> 00:13:29.200
<v Speaker 2>when wheel, when gear. That kind of toad should grab

264
00:13:29.279 --> 00:13:32.159
<v Speaker 2>your attention as if it were playing trumpets. It usually

265
00:13:32.240 --> 00:13:34.480
<v Speaker 2>means there's a hidden duck type, a shared role or

266
00:13:34.519 --> 00:13:38.080
<v Speaker 2>interface waiting to be discovered. For example, maybe different objects

267
00:13:38.120 --> 00:13:40.799
<v Speaker 2>all know how to prepare themselves. Instead of checking their class,

268
00:13:40.799 --> 00:13:43.639
<v Speaker 2>you just call prepare on them. You've identified a preparer

269
00:13:43.720 --> 00:13:46.600
<v Speaker 2>duck type. This makes your code way more flexible. You

270
00:13:46.639 --> 00:13:48.960
<v Speaker 2>can add new kinds of preparers later without changing the

271
00:13:48.960 --> 00:13:52.000
<v Speaker 2>code that uses them. It's easier to extend but casting

272
00:13:52.000 --> 00:13:54.360
<v Speaker 2>a veil over the underlying class, which is often a

273
00:13:54.360 --> 00:13:54.720
<v Speaker 2>good thing.

274
00:13:55.000 --> 00:13:58.919
<v Speaker 1>Okay, so that's dynamic behavior with ducks. What about more structured,

275
00:13:59.000 --> 00:14:01.679
<v Speaker 1>hierarchical behavior using classical inheritance.

276
00:14:01.879 --> 00:14:06.759
<v Speaker 2>Inheritance is basically automatic message delegation. It's like a family tree.

277
00:14:07.080 --> 00:14:11.480
<v Speaker 2>A subclass automatically inherits behavior from its superclass. Subclasses are

278
00:14:11.480 --> 00:14:15.000
<v Speaker 2>the specializations of their superclasses. A mountain bike is a

279
00:14:15.000 --> 00:14:18.120
<v Speaker 2>special kind of bicycle. Finding the right abstraction level and

280
00:14:18.200 --> 00:14:21.639
<v Speaker 2>inheritance can be tricky. The book suggests a strategy push

281
00:14:21.679 --> 00:14:24.480
<v Speaker 2>everything down and then pull some things up. Start by

282
00:14:24.480 --> 00:14:28.519
<v Speaker 2>making things specific in subclasses. Then identify common code or

283
00:14:28.559 --> 00:14:31.519
<v Speaker 2>behavior and carefully pull it up into a shared superclass.

284
00:14:31.799 --> 00:14:34.039
<v Speaker 2>Throughout this, you should constantly ask what will happen when

285
00:14:34.080 --> 00:14:37.759
<v Speaker 2>I'm wrong. This encourages making conservative choices, keeping the cost

286
00:14:37.759 --> 00:14:38.840
<v Speaker 2>of future changes low.

287
00:14:39.120 --> 00:14:42.600
<v Speaker 1>Inheritance can get tricky, especially with super when subclasses have

288
00:14:42.639 --> 00:14:46.759
<v Speaker 1>to remember to call their parents' implementation. That seems error prone.

289
00:14:46.919 --> 00:14:50.240
<v Speaker 2>It definitely is, and that's where the template method pattern shines.

290
00:14:50.320 --> 00:14:53.840
<v Speaker 2>Often using hook methods. Think of the superclass providing a

291
00:14:53.879 --> 00:14:57.759
<v Speaker 2>template an overall algorithm, but it defines placeholder methods. The

292
00:14:57.840 --> 00:15:01.960
<v Speaker 2>hooks like post initialized for customs, setup or local spares

293
00:15:01.960 --> 00:15:06.200
<v Speaker 2>for bike specific parts. Subclasses can then override these hooks

294
00:15:06.240 --> 00:15:09.200
<v Speaker 2>to plug in their specific behavior without needing to explicitly

295
00:15:09.240 --> 00:15:12.799
<v Speaker 2>call super in the main method. This structure removes the

296
00:15:12.799 --> 00:15:15.960
<v Speaker 2>need for subclasses to send super in many cases and

297
00:15:16.080 --> 00:15:19.799
<v Speaker 2>dramatically reduces coupling between the layers. It makes the hierarchy

298
00:15:19.919 --> 00:15:25.360
<v Speaker 2>much cleaner. General advice create shallow hierarchies. Deep inheritance trees

299
00:15:25.399 --> 00:15:28.000
<v Speaker 2>build up a lot of dependencies and become hard to manage.

300
00:15:28.320 --> 00:15:29.360
<v Speaker 2>Keep it simple if you can.

301
00:15:29.840 --> 00:15:32.799
<v Speaker 1>All right, So we have ducks for dynamic behavior, inheritance

302
00:15:32.840 --> 00:15:37.480
<v Speaker 1>for hierarchical specialization. What about combining distinct things together composition.

303
00:15:37.919 --> 00:15:42.000
<v Speaker 2>Composition is about building complex objects by combining smaller, independent parts.

304
00:15:42.039 --> 00:15:44.639
<v Speaker 2>It's a has a relationship. A car has an engine,

305
00:15:44.720 --> 00:15:47.000
<v Speaker 2>has a wheels. The whole becomes more than the sum

306
00:15:47.000 --> 00:15:49.879
<v Speaker 2>of its parts. Like notes forming music, the parts work together.

307
00:15:49.960 --> 00:15:52.679
<v Speaker 1>And the book's recumbent bike example really drives this home

308
00:15:52.799 --> 00:15:53.600
<v Speaker 1>right Well, it's.

309
00:15:53.519 --> 00:15:57.159
<v Speaker 2>A fantastic example. Using inheritance. Adding support for a new

310
00:15:57.200 --> 00:16:00.200
<v Speaker 2>recumbent bike took like nineteen lines of code chain just

311
00:16:00.200 --> 00:16:04.679
<v Speaker 2>scattered around, But by refactoring to use composition. Where a

312
00:16:04.679 --> 00:16:07.840
<v Speaker 2>bicycle has a parts object created by a parts factory,

313
00:16:08.000 --> 00:16:11.120
<v Speaker 2>adding the recumbent bike became just three lines of configuration.

314
00:16:11.600 --> 00:16:14.039
<v Speaker 2>That's it. It shows the power of composition for managing

315
00:16:14.080 --> 00:16:17.000
<v Speaker 2>variations and adding new features. The decision rule of the

316
00:16:17.039 --> 00:16:20.279
<v Speaker 2>book offers is pretty stark. If you cannot explicitly defend

317
00:16:20.279 --> 00:16:22.840
<v Speaker 2>inheritance as a better solution, use composition.

318
00:16:23.200 --> 00:16:27.159
<v Speaker 1>Inheritance carries more risk, so composition is generally preferred unless

319
00:16:27.159 --> 00:16:29.559
<v Speaker 1>there's as strong is a relationship. What are the main

320
00:16:29.600 --> 00:16:31.759
<v Speaker 1>benefits and drawbacks exactly?

321
00:16:32.200 --> 00:16:36.919
<v Speaker 2>Composition usually leads to systems that are more transparent, usable, reasonable,

322
00:16:36.960 --> 00:16:40.559
<v Speaker 2>and have a high tolerance for change. The parts are independent,

323
00:16:40.639 --> 00:16:43.759
<v Speaker 2>easier to test, easier to swamp out. The main cost

324
00:16:43.840 --> 00:16:47.159
<v Speaker 2>is that sometimes the overall structure the whole might feel

325
00:16:47.440 --> 00:16:50.639
<v Speaker 2>less obvious than a clear inheritance try and you often

326
00:16:50.679 --> 00:16:53.440
<v Speaker 2>need to write explicit delegation code to pass messages from

327
00:16:53.440 --> 00:16:56.080
<v Speaker 2>the whole object to its parts. But the guideline holds.

328
00:16:56.720 --> 00:17:01.159
<v Speaker 2>Use inheritance for is a relationships, true specialistation, low risk,

329
00:17:01.240 --> 00:17:05.599
<v Speaker 2>shallow hierarchies. Use composition for has relationships. When an object

330
00:17:05.640 --> 00:17:08.759
<v Speaker 2>is built from distinct parts, composition is usually the safer,

331
00:17:08.839 --> 00:17:10.000
<v Speaker 2>more flexible.

332
00:17:09.559 --> 00:17:13.119
<v Speaker 1>Bet Okay, awesome. We've designed our flexible system using these principles.

333
00:17:13.200 --> 00:17:15.119
<v Speaker 1>Now how do we make sure it actually works and

334
00:17:15.160 --> 00:17:18.359
<v Speaker 1>stays working? Testing and the book argues the purpose isn't

335
00:17:18.359 --> 00:17:19.759
<v Speaker 1>just finding bugs.

336
00:17:19.519 --> 00:17:22.599
<v Speaker 2>Not at all. Just like design, the true purpose of

337
00:17:22.680 --> 00:17:26.640
<v Speaker 2>testing is to reduce costs. Good tests make changes cheaper

338
00:17:26.640 --> 00:17:30.279
<v Speaker 2>and safer. Bad tests or hard to write tests increase costs.

339
00:17:30.359 --> 00:17:33.079
<v Speaker 2>And there's a direct link. Tests are the canary in

340
00:17:33.119 --> 00:17:35.880
<v Speaker 2>the coal mine when the design is bad. Testing is hard.

341
00:17:36.240 --> 00:17:38.440
<v Speaker 2>If your tests are painful to write, it's often assign

342
00:17:38.480 --> 00:17:39.640
<v Speaker 2>your design needs improving.

343
00:17:39.920 --> 00:17:43.319
<v Speaker 1>That's a powerful connection. If testing is about reducing costs,

344
00:17:43.359 --> 00:17:46.039
<v Speaker 1>how does that change what we test? How do we

345
00:17:46.079 --> 00:17:47.519
<v Speaker 1>write cost effective tests?

346
00:17:47.720 --> 00:17:50.680
<v Speaker 2>It radically shifts the focus away from just code coverage

347
00:17:50.960 --> 00:17:54.720
<v Speaker 2>towards testing behavior and interfaces. The guidelines are pretty clear.

348
00:17:55.160 --> 00:17:59.440
<v Speaker 2>Test incoming messages that change state, So incoming messages should

349
00:17:59.440 --> 00:18:01.960
<v Speaker 2>be tested for the state they return. If you call

350
00:18:02.000 --> 00:18:04.400
<v Speaker 2>deposit one hundred, test that the balance is now one

351
00:18:04.440 --> 00:18:09.359
<v Speaker 2>hundred higher. Test outgoing commands. Outgoing command messages should be

352
00:18:09.440 --> 00:18:12.200
<v Speaker 2>tested to ensure they get sent. If your object is

353
00:18:12.200 --> 00:18:14.680
<v Speaker 2>supposed to tell another object to send mail, tests that

354
00:18:14.720 --> 00:18:17.160
<v Speaker 2>the send to mail message was sent, not the details

355
00:18:17.160 --> 00:18:21.880
<v Speaker 2>of how. But importantly, don't test outgoing queries. Outgoing query

356
00:18:21.880 --> 00:18:25.160
<v Speaker 2>messages should not be tested if your object just asks

357
00:18:25.200 --> 00:18:27.960
<v Speaker 2>another object for data like get chooser name and doesn't

358
00:18:28.000 --> 00:18:30.680
<v Speaker 2>change anything. You don't need to test that interaction directly

359
00:18:30.680 --> 00:18:33.720
<v Speaker 2>in the calling objects test testing the query method itself

360
00:18:33.759 --> 00:18:36.799
<v Speaker 2>is enough. This approach minimizes the coupling between your tests

361
00:18:36.839 --> 00:18:40.240
<v Speaker 2>and the implementation details, making tests less brittle and cheaper

362
00:18:40.279 --> 00:18:42.119
<v Speaker 2>to maintain when the code changes. Makes sense.

363
00:18:42.160 --> 00:18:44.799
<v Speaker 1>What about test doubles, stubs and mocks. They can sometimes

364
00:18:44.799 --> 00:18:48.559
<v Speaker 1>create this alternate universe where tests pass but the real

365
00:18:48.599 --> 00:18:49.599
<v Speaker 1>app is broken. Right.

366
00:18:49.799 --> 00:18:53.079
<v Speaker 2>Yeah, that's a real danger. Your doubles might behave slightly

367
00:18:53.119 --> 00:18:56.400
<v Speaker 2>differently than the real objects, leading to false confidence. The

368
00:18:56.440 --> 00:18:59.400
<v Speaker 2>way to combat this is by using tests to document

369
00:18:59.480 --> 00:19:02.799
<v Speaker 2>roles or interfaces. You can actually write tests for your

370
00:19:02.799 --> 00:19:07.799
<v Speaker 2>test doubles. For example, create a diameterizable interface test. Any

371
00:19:07.880 --> 00:19:11.119
<v Speaker 2>object claiming to be usable as a diameterizable thing, like

372
00:19:11.160 --> 00:19:13.519
<v Speaker 2>your real wheel and your diameter double used in tests,

373
00:19:13.880 --> 00:19:17.359
<v Speaker 2>must pass this interface test. This ensures your test doubles

374
00:19:17.559 --> 00:19:20.759
<v Speaker 2>honor the interface this test expects and keeps them synchronized

375
00:19:20.799 --> 00:19:22.240
<v Speaker 2>with the real object's behavior.

376
00:19:22.359 --> 00:19:26.119
<v Speaker 1>Okay, interesting. What about testing private methods? Big debate there sometimes?

377
00:19:26.319 --> 00:19:29.599
<v Speaker 2>Huh. Yes, The book's advice is wonderfully pragmatic and a

378
00:19:29.599 --> 00:19:32.559
<v Speaker 2>bit cheeky. Never write them, and if you do, never

379
00:19:32.599 --> 00:19:34.759
<v Speaker 2>ever test them, unless, of course, it makes sense to

380
00:19:34.799 --> 00:19:38.319
<v Speaker 2>do so. Basically, testing private methods directly is usually a

381
00:19:38.319 --> 00:19:42.000
<v Speaker 2>bad idea. It couples your test tightly to implementation details

382
00:19:42.000 --> 00:19:45.000
<v Speaker 2>that should be free to change. If the public interface works,

383
00:19:45.079 --> 00:19:48.559
<v Speaker 2>the privates are probably okay. However, the unless is important

384
00:19:48.960 --> 00:19:51.599
<v Speaker 2>if you're dealing with a really complex private method, maybe

385
00:19:51.599 --> 00:19:54.720
<v Speaker 2>as part of a temporary refactoring. Writing a targeted test

386
00:19:54.759 --> 00:19:58.000
<v Speaker 2>for it can sometimes reduce the barriers to refactoring by

387
00:19:58.039 --> 00:20:00.359
<v Speaker 2>giving you confidence as you clean it up. But treth

388
00:20:00.359 --> 00:20:02.039
<v Speaker 2>those tests as temporary got it.

389
00:20:02.759 --> 00:20:06.640
<v Speaker 1>And finally, testing code that uses inheritance where subclasses rely

390
00:20:06.720 --> 00:20:08.400
<v Speaker 1>on shared superclass behavior.

391
00:20:08.799 --> 00:20:11.440
<v Speaker 2>This is where those interface tests and what the book

392
00:20:11.480 --> 00:20:15.920
<v Speaker 2>calls subclass responsibility tests really shine. You can write tests

393
00:20:15.960 --> 00:20:19.960
<v Speaker 2>that define the contract a subclass must fulfill to work

394
00:20:20.000 --> 00:20:24.039
<v Speaker 2>correctly with the superclass, template method or hooks. These tests

395
00:20:24.319 --> 00:20:26.480
<v Speaker 2>take all of the pain out of testing the common

396
00:20:26.519 --> 00:20:29.839
<v Speaker 2>behavior of subclasses. A new developer can come on, create

397
00:20:29.880 --> 00:20:32.640
<v Speaker 2>a new subclass, run the tests, and the tests will

398
00:20:32.640 --> 00:20:35.519
<v Speaker 2>tell them exactly which methods they need to implement correctly.

399
00:20:35.920 --> 00:20:37.720
<v Speaker 2>It makes extending hierarchies much safer.

400
00:20:37.920 --> 00:20:45.000
<v Speaker 1>Wow. What an amazing journey through arranging code We've covered responsibilities, dependencies, interfaces, ducts, inheritance,

401
00:20:45.119 --> 00:20:49.079
<v Speaker 1>composition testing. It's a lot, but it connects beautifully, it.

402
00:20:49.000 --> 00:20:51.279
<v Speaker 2>Really does, And that final insight from the book is

403
00:20:51.279 --> 00:20:55.039
<v Speaker 2>so profound. Object oriented design is fractal. The central problem

404
00:20:55.160 --> 00:20:57.799
<v Speaker 2>is to define an extensible way for objects to communicate,

405
00:20:58.160 --> 00:21:00.640
<v Speaker 2>and at every level of magnification, this par looks the

406
00:21:00.680 --> 00:21:03.079
<v Speaker 2>same whether you zoom out to the whole system or

407
00:21:03.119 --> 00:21:06.079
<v Speaker 2>zoom into a single method interacting with its variables. That

408
00:21:06.200 --> 00:21:10.160
<v Speaker 2>core challenge of clear communication and managed dependencies is always there.

409
00:21:10.400 --> 00:21:12.839
<v Speaker 1>Fractal design. That's a fantastic way to think about it.

410
00:21:12.839 --> 00:21:15.480
<v Speaker 1>It scales, and the book leaves us with a final

411
00:21:15.640 --> 00:21:19.039
<v Speaker 1>piece of wisdom, almost a challenge. The rules of design

412
00:21:19.079 --> 00:21:22.039
<v Speaker 1>are meant to be broken. Learning to break them well

413
00:21:22.200 --> 00:21:23.680
<v Speaker 1>is a designer's greatest strength.

414
00:21:23.799 --> 00:21:27.640
<v Speaker 2>Absolutely, It's not about blindly following rules. It's about understanding

415
00:21:28.039 --> 00:21:31.119
<v Speaker 2>the principles behind the rules so you know when and

416
00:21:31.160 --> 00:21:37.440
<v Speaker 2>how to bend them effectively. So yeah, persist, practice, experiment, imagine,

417
00:21:37.599 --> 00:21:39.480
<v Speaker 2>do your best work, and all else will follow.

418
00:21:39.680 --> 00:21:41.599
<v Speaker 1>So listening to all this, what's the one thing that

419
00:21:41.640 --> 00:21:43.960
<v Speaker 1>really stands out to you? Maybe it's designing for that

420
00:21:44.000 --> 00:21:48.519
<v Speaker 1>inevitable change or managing that glue of dependencies, or thinking

421
00:21:48.599 --> 00:21:51.759
<v Speaker 1>about ducks, whatever it is, let that idea challenge how

422
00:21:51.799 --> 00:21:54.160
<v Speaker 1>you think about building software next time See where it

423
00:21:54.160 --> 00:21:54.880
<v Speaker 1>takes you
