1
00:00:00,040 --> 00:00:03,400
Welcome to the deep dive. 
Today we're peeling back the 

2
00:00:03,400 --> 00:00:06,360
layers on a concept that's 
really foundational if you're 

3
00:00:06,360 --> 00:00:09,840
serious about building solid, 
high quality software. 

4
00:00:10,080 --> 00:00:13,000
We're talking about testability.
This deep dive. 

5
00:00:13,000 --> 00:00:15,400
Well, it's designed to help you 
understand how to engineer your 

6
00:00:15,400 --> 00:00:18,440
code right from the start. 
So it's not just functional, but

7
00:00:18,440 --> 00:00:21,560
also really easy to verify. 
And that's, you know, crucial 

8
00:00:21,560 --> 00:00:24,720
for a resilient software. 
We've been digging into software

9
00:00:24,720 --> 00:00:27,800
engineering a modern approach by
Marco Tulio Valente. 

10
00:00:28,200 --> 00:00:30,920
Our mission today, it's really 
to pull out but the key insights

11
00:00:30,920 --> 00:00:34,920
on why designing for testability
is often, well, maybe even more 

12
00:00:34,920 --> 00:00:37,680
critical than just writing the 
tests after the fact. 

13
00:00:37,680 --> 00:00:39,520
We've got some practical 
examples from the source that I 

14
00:00:39,520 --> 00:00:42,600
think really illustrate this. 
It might change how you think 

15
00:00:42,600 --> 00:00:44,680
about development a bit. 
Ultimately, it's about building 

16
00:00:44,680 --> 00:00:48,200
software that doesn't just work,
but is also robust, dependable, 

17
00:00:48,280 --> 00:00:51,160
and easy to maintain down the 
road. 

18
00:00:51,560 --> 00:00:54,080
OK, so let's unpack this. 
We talk a lot about writing 

19
00:00:54,080 --> 00:00:56,760
tests, sure, but what does 
testability actually mean? 

20
00:00:57,280 --> 00:00:59,400
The source gives us a nice 
simple definition. 

21
00:00:59,400 --> 00:01:01,720
It basically describes how easy 
it is to test a program. 

22
00:01:01,720 --> 00:01:03,520
Simple as that. 
Now, we've talked before about 

23
00:01:03,520 --> 00:01:05,760
good test, right? 
Following those first 

24
00:01:05,760 --> 00:01:09,560
principles, fast, independent, 
repeatable, self validating, 

25
00:01:09,560 --> 00:01:12,040
timely, and aiming for good 
coverage. 

26
00:01:12,520 --> 00:01:14,760
We even mentioned how branch 
coverage is stricter, more 

27
00:01:14,760 --> 00:01:17,200
thorough than just statement 
coverage, making sure you hit 

28
00:01:17,200 --> 00:01:19,000
all the decision points. 
Right. 

29
00:01:19,480 --> 00:01:22,520
But what's really key here, and 
what the source really hammers 

30
00:01:22,520 --> 00:01:26,040
home, is that testability isn't 
just about writing clever tests 

31
00:01:26,040 --> 00:01:27,960
or chasing high coverage 
numbers. 

32
00:01:28,320 --> 00:01:31,480
The fundamental idea is that a 
big chunk of your effort in 

33
00:01:31,480 --> 00:01:34,880
getting effective testing should
actually go into the design of 

34
00:01:34,880 --> 00:01:37,920
the production code itself, the 
system under test. 

35
00:01:38,680 --> 00:01:42,080
It's a shift in thinking, you 
know, from just validating after

36
00:01:42,080 --> 00:01:45,680
you build to proactively 
building for validation from the

37
00:01:45,680 --> 00:01:48,040
get go. 
It's like an inherent quality of

38
00:01:48,040 --> 00:01:49,920
the software. 
And here's the good news. 

39
00:01:49,920 --> 00:01:51,920
Really. 
The source points out that code 

40
00:01:51,920 --> 00:01:55,640
that already follows good SOLID 
design principles, things we 

41
00:01:55,640 --> 00:01:59,480
discuss all the time, naturally 
tends to be easier to test. 

42
00:01:59,640 --> 00:02:01,960
We're talking about things like 
high cohesion. 

43
00:02:01,960 --> 00:02:03,440
Yeah, keeping related stuff 
together. 

44
00:02:03,440 --> 00:02:05,800
Low coupling so components 
aren't tangled up. 

45
00:02:05,800 --> 00:02:08,680
Single responsibility. 
Each part doing one job well. 

46
00:02:08,680 --> 00:02:10,960
Separating presentation from the
core logic. 

47
00:02:11,120 --> 00:02:13,760
Dependency inversion, even the 
law of Demeter. 

48
00:02:13,760 --> 00:02:15,600
Exactly. 
All those things that make code 

49
00:02:15,600 --> 00:02:17,120
cleaner and more maintainable 
they. 

50
00:02:17,120 --> 00:02:19,640
Also make it more testable. 
It all kind of clicks together. 

51
00:02:19,840 --> 00:02:22,000
It really does. 
And if you connect this to the 

52
00:02:22,000 --> 00:02:25,440
bigger picture, you see that 
good design isn't just like an 

53
00:02:25,440 --> 00:02:28,120
academic exercise or about 
making code look pretty. 

54
00:02:28,600 --> 00:02:32,360
It has real, practical benefits.
Measurable benefits. 

55
00:02:32,640 --> 00:02:34,280
It makes your software 
verifiable. 

56
00:02:34,560 --> 00:02:37,960
When code is well designed, 
decoupled, cohesive, you can 

57
00:02:37,960 --> 00:02:40,040
isolate pieces and test them 
reliably. 

58
00:02:40,360 --> 00:02:43,520
It moves you away from just 
reacting to bugs and towards 

59
00:02:43,520 --> 00:02:45,560
proactively building resilient 
systems. 

60
00:02:46,000 --> 00:02:49,200
It makes maintenance easier, 
debugging faster and builds 

61
00:02:49,200 --> 00:02:51,440
confidence confidence in every 
change. 

62
00:02:51,640 --> 00:02:53,760
That makes a lot of sense. 
You're building in the pathways 

63
00:02:53,760 --> 00:02:55,320
for checking things right from 
the start. 

64
00:02:55,480 --> 00:02:57,600
OK, let's make this concrete. 
Let's look at the examples from 

65
00:02:57,600 --> 00:02:59,360
the source. 
The first one tackles a really 

66
00:02:59,360 --> 00:03:01,960
common situation, building a web
service. 

67
00:03:02,400 --> 00:03:05,880
Imagine a simple Java servlet. 
Its job is to calculate body 

68
00:03:05,880 --> 00:03:09,280
mass index BMI, takes weight, 
takes height, applies the 

69
00:03:09,280 --> 00:03:12,280
formula weight, height, height. 
Sounds super straightforward. 

70
00:03:12,280 --> 00:03:15,280
It does sound simple on the 
surface, but the source shows 

71
00:03:15,560 --> 00:03:18,600
how the initial way you might 
code this often creates a big 

72
00:03:18,600 --> 00:03:22,120
testing problem. 
The original BMI servlet code as

73
00:03:22,120 --> 00:03:25,360
described has direct 
dependencies on Java's servlet 

74
00:03:25,360 --> 00:03:29,560
package types, specifically 
Http://servlet request and 

75
00:03:29,560 --> 00:03:33,000
Http://servlet response. 
These are the core Java objects 

76
00:03:33,000 --> 00:03:35,760
for handling web requests and 
responses, and that direct 

77
00:03:35,760 --> 00:03:38,440
dependency It creates what's 
called a dependency chain. 

78
00:03:38,840 --> 00:03:41,400
If you want to test just the 
doggett method, the core logic, 

79
00:03:41,520 --> 00:03:43,520
you can't just create the 
servlet object easily. 

80
00:03:43,800 --> 00:03:46,400
You'd need to mock up fake 
request and response objects, 

81
00:03:46,440 --> 00:03:47,720
and maybe their dependencies 
too. 

82
00:03:47,920 --> 00:03:50,240
It gets complicated fast. 
Right, like needing the whole 

83
00:03:50,240 --> 00:03:52,160
engine just to test a single 
gear. 

84
00:03:52,160 --> 00:03:54,400
Exactly. 
That tight coupling makes the 

85
00:03:54,400 --> 00:03:56,720
testability of that initial 
design really low. 

86
00:03:56,920 --> 00:04:00,480
Isolated unit testing becomes 
almost impractical without a ton

87
00:04:00,480 --> 00:04:02,320
of setup. 
OK, that definitely sounds like 

88
00:04:02,320 --> 00:04:04,720
a testing nightmare. 
So how does the source suggest 

89
00:04:04,720 --> 00:04:06,880
we fix this? 
How do you untangle that? 

90
00:04:07,000 --> 00:04:09,800
The solution proposed is 
actually quite, and it hinges on

91
00:04:09,800 --> 00:04:10,920
a principle we just talked 
about. 

92
00:04:11,400 --> 00:04:14,160
Extract the core domain logic. 
The problem is that really the 

93
00:04:14,160 --> 00:04:16,880
BMI calculation itself. 
It's that the calculation is 

94
00:04:16,880 --> 00:04:18,480
tangled up with all the web 
server stuff. 

95
00:04:18,959 --> 00:04:22,120
So the fix involves creating a 
separate class that's called BMI

96
00:04:22,120 --> 00:04:24,280
model. 
This new class does only one 

97
00:04:24,280 --> 00:04:27,960
thing, the BMI calculation. 
It takes weight and height as 

98
00:04:27,960 --> 00:04:31,840
simple numbers, returns the BMI.
Crucially, it has 0 dependencies

99
00:04:31,840 --> 00:04:34,400
on any servlet classes, none at 
all. 

100
00:04:34,480 --> 00:04:36,960
This makes the BM model 
incredibly easy to test in 

101
00:04:36,960 --> 00:04:39,000
isolation. 
You can just create it, feed it 

102
00:04:39,000 --> 00:04:42,280
numbers, check the output. 
No web server, no mocks need it.

103
00:04:42,520 --> 00:04:44,800
Now the source is careful to 
point out, and this is 

104
00:04:44,800 --> 00:04:46,920
important, this refactoring 
doesn't test everything. 

105
00:04:47,120 --> 00:04:49,480
It won't test how the servlet 
interacts with the actual web 

106
00:04:49,480 --> 00:04:52,000
request, for example. 
But, and this is the key 

107
00:04:52,000 --> 00:04:54,600
insight, you are thoroughly 
testing the most critical part, 

108
00:04:54,600 --> 00:04:57,280
the core business logic, the 
actual calculation. 

109
00:04:57,480 --> 00:05:00,120
And verifying that core logic is
vastly better than leaving it 

110
00:05:00,120 --> 00:05:04,800
untested or relying only on 
slow, complex integration tests.

111
00:05:05,000 --> 00:05:06,560
You focus your testing up for 
where it counts. 

112
00:05:06,560 --> 00:05:08,640
Most that's a great take away 
for you listening. 

113
00:05:09,120 --> 00:05:12,440
Isolate that core business logic
from its environment and boom, 

114
00:05:12,520 --> 00:05:14,680
testability goes way up. 
You get precision. 

115
00:05:15,400 --> 00:05:19,000
And interestingly, the same 
idea, extraction separation, 

116
00:05:19,000 --> 00:05:21,520
applies even when you're dealing
with a completely different kind

117
00:05:21,520 --> 00:05:23,520
of challenge, like asynchronous 
code. 

118
00:05:24,280 --> 00:05:26,400
Let's shift gears to the second 
example from the source. 

119
00:05:26,560 --> 00:05:29,120
This one looks at asynchronous 
functions, which are notoriously

120
00:05:29,120 --> 00:05:32,520
tricky to test. 
Well, the example is an async Pi

121
00:05:32,520 --> 00:05:34,520
function. 
As you might guess, it 

122
00:05:34,520 --> 00:05:37,520
calculates π but it does it in 
the background, maybe on another

123
00:05:37,520 --> 00:05:39,360
thread, so the result isn't 
immediate. 

124
00:05:39,680 --> 00:05:42,040
Right, and this immediately 
raises a big question. 

125
00:05:42,480 --> 00:05:45,360
Why is async code so hard to 
test reliably? 

126
00:05:46,080 --> 00:05:47,600
The source highlights the main 
problem. 

127
00:05:48,080 --> 00:05:51,320
The result comes from another 
thread, so when it arrives is 

128
00:05:51,320 --> 00:05:53,000
unpredictable, non 
deterministic. 

129
00:05:53,280 --> 00:05:56,720
A common but really problematic 
way people try to test this is 

130
00:05:56,720 --> 00:05:59,960
by putting pauses in their tests
using something like thread dot 

131
00:05:59,960 --> 00:06:02,800
sleep to just wait and hope the 
result is ready. 

132
00:06:02,880 --> 00:06:04,360
Oh. 
Yeah, the dreaded thread dot 

133
00:06:04,360 --> 00:06:06,640
sleep in tests. 
That usually leads to flaky 

134
00:06:06,640 --> 00:06:08,480
tests, right? 
Sometimes they pass, sometimes 

135
00:06:08,480 --> 00:06:10,120
they fail even if the code 
didn't change. 

136
00:06:10,320 --> 00:06:12,840
Exactly. 
It leads to non deterministic or

137
00:06:12,840 --> 00:06:14,800
flaky tests. 
You can't guarantee the 

138
00:06:14,800 --> 00:06:17,040
background work will finish in 
that that fixed pause. 

139
00:06:17,280 --> 00:06:20,080
Maybe the system is busy, maybe 
it takes longer this time. 

140
00:06:20,520 --> 00:06:24,120
This inconsistency just destroys
confidence in your test suite. 

141
00:06:24,280 --> 00:06:27,080
You don't know if a failure is a
real bug or just bad timing. 

142
00:06:27,320 --> 00:06:30,720
So how do you test something 
reliably when its timing is 

143
00:06:30,720 --> 00:06:33,080
inherently unpredictable? 
It sounds like a recipe for 

144
00:06:33,080 --> 00:06:35,000
frustration. 
So what's the solution here? 

145
00:06:35,000 --> 00:06:37,240
I'm guessing it involves 
extraction again. 

146
00:06:37,440 --> 00:06:40,040
You guessed it, it's the same 
powerful pattern. 

147
00:06:40,520 --> 00:06:44,000
The source proposes extracting 
the core π calculation logic 

148
00:06:44,400 --> 00:06:46,480
into a separate synchronous 
function. 

149
00:06:46,720 --> 00:06:49,640
Let's call it sync Pi. 
The sync Pi function does the 

150
00:06:49,640 --> 00:06:52,920
exact same math to calculate π 
but it does it immediately right

151
00:06:52,920 --> 00:06:55,920
there, blocking until it's done.
It's completely separate from 

152
00:06:55,920 --> 00:06:58,160
any threading or asynchronous 
execution. 

153
00:06:58,840 --> 00:07:01,480
This extraction means you can 
reliably unit test the 

154
00:07:01,480 --> 00:07:04,080
calculation itself. 
You call sync Pi, give it 

155
00:07:04,080 --> 00:07:06,760
inputs, get an immediate, 
predictable result back, and 

156
00:07:06,760 --> 00:07:09,680
assert against it. 
Simple, reliable, fast. 

157
00:07:10,120 --> 00:07:12,720
It just reinforces that pattern 
we saw with the servlet example.

158
00:07:13,520 --> 00:07:16,520
Extracting A testicle function, 
one that's pure synchronous, 

159
00:07:16,720 --> 00:07:19,840
with clear inputs and outputs, 
free from tricky dependencies or

160
00:07:19,840 --> 00:07:22,480
timing issues, is always better 
than leaving complex code 

161
00:07:22,480 --> 00:07:24,760
untested or using flaky test 
methods. 

162
00:07:25,080 --> 00:07:28,040
It lets you verify the core 
critical logic with confidence. 

163
00:07:28,400 --> 00:07:29,840
That's such a clear through 
line. 

164
00:07:29,840 --> 00:07:32,400
Whether it's a web service 
handling input or a background 

165
00:07:32,400 --> 00:07:35,080
task doing calculations, 
isolating that core logic is 

166
00:07:35,080 --> 00:07:36,760
key. 
It makes your code predictable 

167
00:07:36,760 --> 00:07:38,640
for testing. 
It absolutely is. 

168
00:07:39,000 --> 00:07:41,520
The central message coming out 
of these examples and from the 

169
00:07:41,600 --> 00:07:43,680
source material generally is 
crystal clear. 

170
00:07:44,000 --> 00:07:46,840
Testability isn't some extra 
thing you tack on at the end. 

171
00:07:47,080 --> 00:07:49,560
It's fundamentally about the 
design of your software. 

172
00:07:50,400 --> 00:07:53,560
By sticking to principles like 
separation of concerns, keeping 

173
00:07:53,560 --> 00:07:57,280
different jobs apart, and by 
actively extracting independent,

174
00:07:57,280 --> 00:08:01,280
testable units, well, you make 
your code inherently easier to 

175
00:08:01,280 --> 00:08:03,240
verify. 
It's not just about making it 

176
00:08:03,240 --> 00:08:05,440
easier to find bugs later. 
It's really about building 

177
00:08:05,440 --> 00:08:08,280
confidence into your software 
right from the start, making it 

178
00:08:08,280 --> 00:08:11,760
robust, maintainable and easier 
to change safely over time. 

179
00:08:12,040 --> 00:08:15,680
It transforms testing from a 
chore into just a natural 

180
00:08:15,680 --> 00:08:17,440
outcome of good design. 
Precisely. 

181
00:08:18,000 --> 00:08:20,440
Well, thank you for joining us 
on this deep dive into software 

182
00:08:20,440 --> 00:08:22,360
testability. 
And that's our deep dive for 

183
00:08:22,360 --> 00:08:23,760
today. 
Thanks for tuning in and 

184
00:08:23,760 --> 00:08:26,720
exploring with us how designing 
for testability can really make 

185
00:08:26,720 --> 00:08:29,320
a difference to the quality and 
longevity of your software.

