-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathchapter-10.srt
782 lines (612 loc) · 15.8 KB
/
chapter-10.srt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
1
00:00:00,000 --> 00:00:03,965
Chapter 10.
Checking the mtime of the Target.
2
00:00:04,140 --> 00:00:09,920
The other thing is they should be lazy.
3
00:00:11,554 --> 00:00:15,920
So if you run the build and make no changes
then run it again nothing should happen.
4
00:00:15,960 --> 00:00:19,325
Builds take a long time as your project grows,
5
00:00:19,360 --> 00:00:24,090
especially minifying
javascript, it can get very slow.
6
00:00:25,090 --> 00:00:30,125
A simple way to do that is to look
at the modified times of the files,
7
00:00:30,228 --> 00:00:35,897
and if any of the things that you depend on
are newer than your own file, then you rebuild.
8
00:00:35,897 --> 00:00:38,971
Otherwise you don't.
9
00:00:39,080 --> 00:00:42,982
TS: Just to clarify can you talk us through...
10
00:00:43,097 --> 00:00:47,954
You've already addressed one case
about unnecessary work being done.
11
00:00:48,020 --> 00:00:52,902
You've made some change to it that
ensures something doesn't get done twice.
12
00:00:52,982 --> 00:00:57,417
And now you're making another change which
is also about something not being done twice,
13
00:00:57,410 --> 00:00:59,782
but in a different way.
14
00:00:59,780 --> 00:01:03,325
TS: So the change you've already made,
15
00:01:03,320 --> 00:01:08,480
what kind of case has that dealt
with that hasn't been dealt with here?
16
00:01:10,520 --> 00:01:15,360
JC: If you have a build that has say a diamond shape...
So you have the thing that you want.
17
00:01:15,622 --> 00:01:20,800
And that depends on two things.
Then they both depend on one thing.
18
00:01:20,960 --> 00:01:24,445
So when you call build here it
will call build on these two,
19
00:01:24,480 --> 00:01:27,554
and then they will both call build on that thing.
20
00:01:27,550 --> 00:01:33,097
What I just did was make it so that
those two builds to the same target
21
00:01:33,188 --> 00:01:38,354
don't cause work to be duplicated
within the same build process.
22
00:01:38,350 --> 00:01:45,211
We're now talking about
when you run your build twice.
23
00:01:45,382 --> 00:01:52,320
That the second time you run it, if you haven't
changed anything, no work should need to be done.
24
00:01:53,074 --> 00:01:56,777
It skips you waiting around for things
that don't need to be recompiled;
25
00:01:56,770 --> 00:01:59,394
or whatever it is that your doing.
26
00:01:59,390 --> 00:02:01,097
TS: OK, Cool.
27
00:02:01,090 --> 00:02:06,594
JC: It's duplicate work within one
build and then across multiple builds.
28
00:02:08,125 --> 00:02:14,914
When you have things going across multiple builds,
like multiple executions of your build tool,
29
00:02:14,994 --> 00:02:17,908
you don't have that information in memory.
30
00:02:17,900 --> 00:02:21,382
We solved the first problem by
putting a flag in memory on an object
31
00:02:21,417 --> 00:02:24,640
to say "don't do this again, you've already done it."
32
00:02:24,765 --> 00:02:26,731
When you have multiple invocations of something
33
00:02:26,742 --> 00:02:30,822
you have to rely on some state
that persists between processes.
34
00:02:30,830 --> 00:02:35,222
In this case that state could be the
modified times of the files you're looking at.
35
00:02:35,234 --> 00:02:39,771
That's why basing this around
files as the primary thing...
36
00:02:40,617 --> 00:02:46,777
It's good because it gives you an almost
free way to check that things are up to date.
37
00:02:46,770 --> 00:02:48,342
TS: OK.
38
00:02:48,770 --> 00:02:55,417
JC: So we have these tests for when
there's dependencies. We could also have ...
39
00:02:57,074 --> 00:03:01,017
What would we like to do here?
So this is the thing that tells the things to build...
40
00:03:01,070 --> 00:03:03,314
Which is what we want to do.
41
00:03:03,410 --> 00:03:09,485
We should then probably also say that
depending on the result of what those calls is,
42
00:03:10,160 --> 00:03:12,228
what is this target going to do?
43
00:03:12,270 --> 00:03:18,342
So if any of those calls return a time
that's higher than the time that I have,
44
00:03:18,445 --> 00:03:21,405
then I should quit.
45
00:03:22,137 --> 00:03:25,462
TS: What does 'higher than' mean?
46
00:03:26,262 --> 00:03:30,971
JC: (I always get this backwards
in time!). I mean later than.
47
00:03:31,005 --> 00:03:33,565
You have your CoffeeScript
file and your JavaScript file.
48
00:03:33,570 --> 00:03:37,222
If the CoffeeScript file was
modified later than the JavaScript file,
49
00:03:37,234 --> 00:03:39,988
that means the JavaScript file is
out of date, so it will recompile it.
50
00:03:40,022 --> 00:03:45,005
If it's the other way round
that means your JavaScript file
51
00:03:45,010 --> 00:03:48,971
has presumably been generated since
the last time you modified the CoffeeScript.
52
00:03:48,994 --> 00:03:51,240
And you don't need to do any more work.
53
00:03:51,240 --> 00:03:59,817
So let's say... We can have some context inside here.
54
00:03:59,810 --> 00:04:12,068
When the dependencies are newer than the target - do.
55
00:04:14,342 --> 00:04:16,868
OK.
56
00:04:17,760 --> 00:04:20,240
So how am I going to model that?
57
00:04:20,280 --> 00:04:44,857
We can say that we allow the first dependency
to receive build and return Time.now plus 5 minutes.
58
00:04:46,400 --> 00:04:55,017
Likewise we'll allow the second
dependency to return time now plus 2 minutes.
59
00:04:59,860 --> 00:05:04,411
The target itself is going to take
those times it got from the dependencies
60
00:05:04,411 --> 00:05:05,988
and then compare them to what it has.
61
00:05:06,000 --> 00:05:11,017
And to do that it's probably going to call File.mtime.
62
00:05:11,210 --> 00:05:13,165
TS: What does mtime mean?
63
00:05:13,234 --> 00:05:14,880
JC: It's the modification time.
64
00:05:14,880 --> 00:05:19,931
The unix file system; every file has
several time stamps attached to it.
65
00:05:19,977 --> 00:05:23,142
And one of those time stamps
is the last time it was modified.
66
00:05:23,177 --> 00:05:26,160
You also get the last time it was
accessed, and some other things.
67
00:05:26,240 --> 00:05:30,600
But when you write to a file, the
file system updates that time stamp
68
00:05:30,628 --> 00:05:33,560
so you can tell the last time it was changed.
69
00:05:33,560 --> 00:05:37,874
TS: Is this the point at which it needs the
pathname that you've been passing in all along?
70
00:05:37,920 --> 00:05:45,188
JC: Yes. I introduced that quite prematurely.
This is the first time that we need it.
71
00:05:46,100 --> 00:05:53,245
Maybe the first thing we should do is
assert that it checks the time of its own pathname.
72
00:05:53,280 --> 00:06:01,268
Checks the mtime of its own file.
73
00:06:01,554 --> 00:06:14,262
So we expect file to receive mtime with pathname.
74
00:06:15,200 --> 00:06:23,257
I'll change that up here to
make it less of a generic name.
75
00:06:23,570 --> 00:06:27,234
Or target/pathname.
76
00:06:27,640 --> 00:06:33,531
[Silence]
77
00:06:33,691 --> 00:06:39,028
Return some time value here,
we don't really care what it is.
78
00:06:39,428 --> 00:06:45,577
So when you call target.build that should happen.
79
00:06:45,970 --> 00:06:48,617
I've just realised this test
isn't part of this context...
80
00:06:48,628 --> 00:06:50,925
It doesn't need these things to be true.
81
00:06:51,028 --> 00:06:53,211
So we can move that out.
82
00:06:53,257 --> 00:06:57,234
TS: Is it something that
always has to happen regardless?
83
00:06:59,040 --> 00:07:06,205
JC: Yes. I'm thinking this
through a little bit in reverse.
84
00:07:06,468 --> 00:07:11,120
Thinking it's going to look at its dependencies'
times and then compare them to itself.
85
00:07:11,165 --> 00:07:16,240
Therefore I should write a test to say
that it asks the file system for some information
86
00:07:17,050 --> 00:07:18,914
But I realised that wasn't part of this.
87
00:07:18,925 --> 00:07:23,142
So we can check that it does this and then
given that the dependencies return some values,
88
00:07:23,154 --> 00:07:25,794
how does it compare with
what it knows about itself.
89
00:07:25,862 --> 00:07:30,080
TS: I'm having trouble conceptualizing these
dependencies that were built in the future.
90
00:07:30,354 --> 00:07:38,125
But it's relative to what you're imagining. We're
imagining the Time.now is the mtime of this target.
91
00:07:38,120 --> 00:07:44,171
JC: Yes and I'm just doing that because hard coding
time values always ends up blowing up in my face.
92
00:07:45,657 --> 00:07:48,811
You know, six months later your
build starts failing for no reason,
93
00:07:48,810 --> 00:07:55,405
so I usually do them as offsets
from wherever you are right now.
94
00:07:55,577 --> 00:08:00,388
I could have put them in the past but it doesn't
make much difference, it's the relative offset.
95
00:08:00,674 --> 00:08:08,640
This will fail now because we're not doing that,
we're not checking the mtime so this won't work.
96
00:08:11,150 --> 00:08:17,680
"received unexpected message :build with (no args)"
in target_spec.rb line 28.
97
00:08:17,950 --> 00:08:23,348
[Silence]
98
00:08:23,440 --> 00:08:28,662
Oh right, it's telling those things to build.
That's fine, we just need to give them a build method.
99
00:08:28,940 --> 00:08:34,708
[Silence]
100
00:08:34,982 --> 00:08:38,537
It's only later we say that that
build method should return something.
101
00:08:38,530 --> 00:08:41,005
In this test it's not important what they return.
102
00:08:41,250 --> 00:08:49,085
I'm trying to keep the doubles to express the
minimum interface they need to make the test work.
103
00:08:49,131 --> 00:08:52,580
TS: So you didn't need to do this before because
there was only one example in this context,
104
00:08:52,594 --> 00:08:56,571
and that had expectations on those doubles.
105
00:08:56,780 --> 00:09:03,005
JC: Right, yes. I wrote this
test down here, that stubs it.
106
00:09:03,142 --> 00:09:09,691
But for this test, those don't apply so
I had to put build method on them up top.
107
00:09:11,931 --> 00:09:17,954
Now it's failing for the right reason and
File isn't receiving mtime with the right things.
108
00:09:17,950 --> 00:09:21,862
So let's go and fix that.
109
00:09:22,068 --> 00:09:29,337
So build_self, we're already returning
"we're already built" so that's an easy, cheap check.
110
00:09:29,474 --> 00:09:35,600
If that fails we don't want to call the file system
if we know we've already built, it's a waste of some IO.
111
00:09:37,210 --> 00:09:39,977
So we'll look at the mtime.
112
00:09:43,140 --> 00:09:49,211
We don't need that variable to pass that test, we
just need to call File.mtime with our path name.
113
00:09:49,690 --> 00:09:51,954
TS: So this is the piece of
state you we're talking about.
114
00:09:51,977 --> 00:09:54,365
We update these mtimes when we run the build.
115
00:09:54,360 --> 00:09:59,725
And then next time we run a build we can look to see
if someone else has been in and changed something.
116
00:09:59,748 --> 00:10:05,800
JC: Yes, and you can set that explicitly yourself.
You can tell unix to set the mtime of this file to this.
117
00:10:05,840 --> 00:10:09,180
But it also happens implicitly
when you write to a file.
118
00:10:09,220 --> 00:10:13,074
That's why this is the first time it's appeared so far.
119
00:10:15,931 --> 00:10:17,108
TS: Wow.
120
00:10:17,188 --> 00:10:21,497
JC: That was... Loads of things just blew up.
121
00:10:21,800 --> 00:10:28,182
[Silence]
122
00:10:28,822 --> 00:10:31,451
No such file or directory.
123
00:10:34,910 --> 00:10:38,514
Most of these tests are using
file names that don't exist.
124
00:10:38,582 --> 00:10:42,434
This is the only test where we
mentioned a mock expectation on File.mtime.
125
00:10:42,457 --> 00:10:45,382
All the other tests are
actually going to be calling it.
126
00:10:45,380 --> 00:10:50,491
And then it will fail because you've
asked for a file that doesn't exist.
127
00:10:50,868 --> 00:10:56,845
So this is another bit of system stuff
that we need to stub out in all the tests.
128
00:10:56,960 --> 00:11:00,468
So allow target to receive system and return true.
129
00:11:00,610 --> 00:11:03,577
The other targets in these tests
are doubles so that doesn't matter.
130
00:11:03,630 --> 00:11:20,640
But we're also going to allow File
to receive mtime and return Time.now.
131
00:11:21,497 --> 00:11:24,742
Remove parentheses for consistency.
132
00:11:26,000 --> 00:11:30,582
TS: Is it important that it does
return a specific value at this stage?
133
00:11:30,700 --> 00:11:35,817
JC: Not at this stage because we're
not using it so let's remove the .....
134
00:11:35,851 --> 00:11:40,960
TS: But your imagining that at some point you
want to control the mtime that comes back from this.
135
00:11:40,960 --> 00:11:47,062
JC: Yes. The next thing we will do is use that
value and compare it to some other things,
136
00:11:47,060 --> 00:11:49,942
and at that point having the right
value at the right time will be important.
137
00:11:49,940 --> 00:11:52,777
TS: And that's why you had to
come back and put return true in here
138
00:11:52,800 --> 00:11:57,451
to make it so that stuff didn't
think that system had failed.
139
00:11:57,520 --> 00:12:09,611
JC: Exactly, but on line 27 nothing is using that
value so it's probably safe to have it return nil.
140
00:12:11,805 --> 00:12:18,651
So we're still getting one fail and that's
in the integration tests: for the same reason.
141
00:12:18,910 --> 00:12:29,017
[Silence]
142
00:12:30,034 --> 00:12:32,640
TS: Should the integration test now actually work?
143
00:12:32,914 --> 00:12:34,650
JC: You're right, the integration test should work.
144
00:12:34,674 --> 00:12:38,285
And I shouldn't be stubbing things in
the integration test. It's using real files.
145
00:12:38,297 --> 00:12:41,880
TS: So what's the problem?
146
00:12:42,171 --> 00:12:45,622
JC: "No such file or directory"
147
00:12:45,760 --> 00:12:49,737
TS: Is this the target that's trying to build one.txt?
148
00:12:51,200 --> 00:12:55,657
JC: Right yes, I've told the
dependencies to update themselves.
149
00:12:55,650 --> 00:13:00,274
Then I'm saying what's the mtime of my
file; but I might not have built my file yet.
150
00:13:00,300 --> 00:13:04,080
TS: So this is the special case when
you're running the build for the first time.
151
00:13:04,102 --> 00:13:06,034
And this file doesn't exist yet.
152
00:13:06,068 --> 00:13:11,211
JC: Exactly. It's happening
recursively so that what's going wrong.
153
00:13:11,302 --> 00:13:14,982
So, it's actually the code that's wrong.
154
00:13:15,051 --> 00:13:18,170
TS: I guess this is why we have integration tests.
155
00:13:18,205 --> 00:13:26,880
JC: Yes. So we can check the file exists first.
156
00:13:30,460 --> 00:13:33,554
That's a start.
157
00:13:33,920 --> 00:13:37,165
Now we're back to something reasonable.
158
00:13:37,188 --> 00:13:38,925
TS: So that fixed your integration test?
159
00:13:38,920 --> 00:13:44,102
JC: Yes, but now the unit test is failing because
this is still a fake pathname that doesn't exist.
160
00:13:44,100 --> 00:13:49,314
When you call File.exists with it it won't work.
161
00:13:50,525 --> 00:13:57,817
So we'll also have to stub that in the unit test.
162
00:13:57,970 --> 00:14:08,925
Which means we can, in general, bypass that
whole code path by having this return false.
163
00:14:09,130 --> 00:14:12,194
Then we won't need to stub more things.
164
00:14:12,190 --> 00:14:16,320
But in the case where were doing this...
165
00:14:16,342 --> 00:14:33,600
We also need to expect file to receive
exists with target/pathname and return true.
166
00:14:34,620 --> 00:14:36,182
I could write a bunch of tests...
167
00:14:36,194 --> 00:14:39,880
Like, if the file exists it checks the thing
or if it doesn't exist it doesn't check the thing,
168
00:14:39,880 --> 00:14:43,474
but it's sort of implicit in
that something already failed,
169
00:14:43,470 --> 00:14:45,577
that made me write the file exists check.
170
00:14:45,600 --> 00:14:49,908
So I'm not desperate about
writing those tests right now.