1 00:00:06,570 --> 00:00:08,950 - All right, now that we have that concrete implementation, 2 00:00:08,950 --> 00:00:12,110 let's go ahead and look at how we can decouple this code 3 00:00:12,110 --> 00:00:13,090 from change. 4 00:00:13,090 --> 00:00:15,126 Now, one of the very first things we want to look at 5 00:00:15,126 --> 00:00:18,200 is the lower level API. 6 00:00:18,200 --> 00:00:21,500 The lower level API was this, it was pull and store. 7 00:00:21,500 --> 00:00:25,020 What we need to do is decouple pull from the concrete. 8 00:00:25,020 --> 00:00:26,540 Nothing that pull knows about 9 00:00:26,540 --> 00:00:27,540 should be based on the concrete. 10 00:00:27,540 --> 00:00:28,860 It has to be based on what? 11 00:00:28,860 --> 00:00:31,330 Decoupling our interface. 12 00:00:31,330 --> 00:00:33,410 To understand what interface we're supposed to use, 13 00:00:33,410 --> 00:00:34,760 I don't have to guess. 14 00:00:34,760 --> 00:00:38,320 I already have an implementation of the lower level API. 15 00:00:38,320 --> 00:00:40,740 Remember, I've implemented Xenia, 16 00:00:40,740 --> 00:00:42,440 and Xenia knows how to pull. 17 00:00:42,440 --> 00:00:45,160 I've implemented Pillar and Pillar knows how to store. 18 00:00:45,160 --> 00:00:49,280 Look at this, my concrete implementation has provided us 19 00:00:49,280 --> 00:00:52,220 the behavior that we're going to use 20 00:00:52,220 --> 00:00:54,580 to decouple us from the concrete. 21 00:00:54,580 --> 00:00:56,290 This is why I don't want you to start 22 00:00:56,290 --> 00:00:59,070 with the behavior or the interfaces, 23 00:00:59,070 --> 00:01:01,580 we start with the concrete implementation. 24 00:01:01,580 --> 00:01:04,850 Let's go ahead and lay in those interfaces now. 25 00:01:04,850 --> 00:01:05,980 I'm going to come in here 26 00:01:05,980 --> 00:01:07,620 and I'm going to add two interfaces. 27 00:01:07,620 --> 00:01:10,510 There it is, the Puller interface that knows how to pull, 28 00:01:10,510 --> 00:01:14,220 and the Storer interface that knows how to store. 29 00:01:14,220 --> 00:01:17,270 I'm not guessing, I already have a strong implementation 30 00:01:17,270 --> 00:01:19,160 of pull and store, we've worked this out, 31 00:01:19,160 --> 00:01:20,780 we've got a working program in production. 32 00:01:20,780 --> 00:01:22,420 We know these APIs are good. 33 00:01:22,420 --> 00:01:24,450 We also know everything was fast enough. 34 00:01:24,450 --> 00:01:26,290 I didn't have to worry about my primitive layer 35 00:01:26,290 --> 00:01:29,730 being too slow, remember, it was fast enough, life is good. 36 00:01:29,730 --> 00:01:31,830 Now we can go ahead and decouple. 37 00:01:31,830 --> 00:01:34,080 Let's go into our lower level API, 38 00:01:34,080 --> 00:01:35,800 replace Xenia with Puller, 39 00:01:35,800 --> 00:01:38,560 and now we can use the Puller interface 40 00:01:38,560 --> 00:01:39,980 to execute the behavior. 41 00:01:39,980 --> 00:01:41,800 We have the highest level of decoupling 42 00:01:41,800 --> 00:01:45,130 we can achieve in Go, it is thin, and it is precise. 43 00:01:45,130 --> 00:01:47,310 We're asking for any piece of concrete data, 44 00:01:47,310 --> 00:01:50,760 any value or any pointer that knows how to pull, 45 00:01:50,760 --> 00:01:52,470 and we do it again with store. 46 00:01:52,470 --> 00:01:55,210 Give me any piece of concrete data, any value, 47 00:01:55,210 --> 00:01:57,520 any pointer that knows how to store, 48 00:01:57,520 --> 00:02:00,240 and we do that through the API. 49 00:02:00,240 --> 00:02:03,220 Look, all I've done is replaced my lower level API 50 00:02:03,220 --> 00:02:06,530 with a layer of decoupling, and guess what? 51 00:02:06,530 --> 00:02:10,010 Boom, now I can create other concrete types 52 00:02:10,010 --> 00:02:13,830 for other systems and that lower level API 53 00:02:13,830 --> 00:02:15,700 can work with those other systems. 54 00:02:15,700 --> 00:02:17,150 Now, we're still not done yet. 55 00:02:17,150 --> 00:02:19,157 We've got to decouple all the way through main, 56 00:02:19,157 --> 00:02:21,210 and the only code you should have to change 57 00:02:21,210 --> 00:02:23,374 is main before Copy. 58 00:02:23,374 --> 00:02:27,150 Copy right now is working with the concrete type System. 59 00:02:27,150 --> 00:02:29,830 It would be nice to also decouple Copy, 60 00:02:29,830 --> 00:02:31,583 so it could work with any System 61 00:02:31,583 --> 00:02:34,170 that knows how to pull and store, right? 62 00:02:34,170 --> 00:02:36,060 Let's go ahead and now go ahead 63 00:02:36,060 --> 00:02:38,590 and we'll add a third interface. 64 00:02:38,590 --> 00:02:39,880 What's cool about this is, 65 00:02:39,880 --> 00:02:43,750 we can also leverage composition at the interface level. 66 00:02:43,750 --> 00:02:47,740 Look at that, that is the PullStorer interface, 67 00:02:47,740 --> 00:02:49,800 and it's a very common naming convention, 68 00:02:49,800 --> 00:02:51,760 it's very idiomatic in Go to, 69 00:02:51,760 --> 00:02:53,970 when we compose two other interfaces, 70 00:02:53,970 --> 00:02:56,350 to use that PullStorer, kind of, 71 00:02:56,350 --> 00:02:59,801 we see it with read closures and write closures, 72 00:02:59,801 --> 00:03:02,180 and here we are, the PullStorer. 73 00:03:02,180 --> 00:03:04,630 Now, through composition embedding, 74 00:03:04,630 --> 00:03:06,140 now, any piece of concrete data 75 00:03:06,140 --> 00:03:09,160 that knows how to pull and store is also a PullStorer. 76 00:03:09,160 --> 00:03:11,600 Isn't System already a PullStorer 77 00:03:11,600 --> 00:03:14,290 thanks to the composition of Xenia and Pillar? 78 00:03:14,290 --> 00:03:15,320 It absolutely is. 79 00:03:15,320 --> 00:03:17,010 Our concrete type system already knows 80 00:03:17,010 --> 00:03:18,470 how to pull and store. 81 00:03:18,470 --> 00:03:20,050 Look at what we're able to do. 82 00:03:20,050 --> 00:03:23,258 We're able to now pull System out of the API, 83 00:03:23,258 --> 00:03:25,460 another refactor, say PullStorer, 84 00:03:25,460 --> 00:03:28,140 System already implements the PullStorer interface, 85 00:03:28,140 --> 00:03:30,080 which now means that in main, 86 00:03:30,080 --> 00:03:33,610 and when I pass a copy of the System pointer, 87 00:03:33,610 --> 00:03:37,330 it already implements PullStorer, and this code now, 88 00:03:37,330 --> 00:03:40,260 at least from the lower level and the higher level API, 89 00:03:40,260 --> 00:03:42,920 is completely decoupled from change. 90 00:03:42,920 --> 00:03:46,570 But there's something very interesting in Copy 91 00:03:46,570 --> 00:03:48,050 that might concern you. 92 00:03:48,050 --> 00:03:50,310 It concerns me initially. 93 00:03:50,310 --> 00:03:54,240 I want you to look at the calls to pull and store. 94 00:03:54,240 --> 00:03:59,240 You may not realize this, but we're passing the PS variable 95 00:04:00,480 --> 00:04:04,000 into pull, and the PS variable into store. 96 00:04:04,000 --> 00:04:05,930 This should take some alarm. 97 00:04:05,930 --> 00:04:08,000 Whoa, whoa, whoa, whoa, whoa, whoa, Bill. 98 00:04:08,000 --> 00:04:09,887 Pull isn't looking for a PullStorer. 99 00:04:09,887 --> 00:04:13,680 Pull's looking for a puller, store's looking for a storer, 100 00:04:13,680 --> 00:04:15,980 PS is not a puller or a storer. 101 00:04:15,980 --> 00:04:18,500 Why is this code compiling? 102 00:04:18,500 --> 00:04:20,410 Well, let's do the following. 103 00:04:20,410 --> 00:04:22,180 Let's walk through this code 104 00:04:22,180 --> 00:04:25,630 and I'll explain to you why this code's able to compile. 105 00:04:25,630 --> 00:04:28,220 We start with our system, here it is. 106 00:04:28,220 --> 00:04:32,690 Remember, our system is the embedding of Xenia and Pillar. 107 00:04:32,690 --> 00:04:35,980 We know Xenia knows how to pull, Pillar knows how to store, 108 00:04:35,980 --> 00:04:38,680 so our system knows how to pull, 109 00:04:38,680 --> 00:04:40,720 and our system knows how to store. 110 00:04:40,720 --> 00:04:41,720 Right, we're getting all of this 111 00:04:41,720 --> 00:04:44,140 through the inter type promotion. 112 00:04:44,140 --> 00:04:47,470 Now, we take the address of System on the call to Copy, 113 00:04:47,470 --> 00:04:48,490 and when we get to Copy, 114 00:04:48,490 --> 00:04:50,530 remember Copy's completely decoupled, 115 00:04:50,530 --> 00:04:52,190 it has the PullStorer interface, 116 00:04:52,190 --> 00:04:54,440 remember, interface values are valueless, 117 00:04:54,440 --> 00:04:57,050 interface types are valueless. 118 00:04:57,050 --> 00:04:59,340 They're saying, give me any concrete type, any value, 119 00:04:59,340 --> 00:05:01,940 any pointer, any piece of concrete data, sorry, 120 00:05:01,940 --> 00:05:03,100 any value, any pointer 121 00:05:03,100 --> 00:05:04,930 that implements the PullStorer interface. 122 00:05:04,930 --> 00:05:06,720 We know System does. 123 00:05:06,720 --> 00:05:10,000 Now, what happens is, we get our PS, 124 00:05:10,000 --> 00:05:12,520 this says I got a pointer to a system, 125 00:05:12,520 --> 00:05:15,810 and we're storing, through pointer semantics, 126 00:05:15,810 --> 00:05:17,380 our system value. 127 00:05:17,380 --> 00:05:20,710 Great, now, here's the interesting part. 128 00:05:20,710 --> 00:05:24,450 We're able to pass PS into pull and store, 129 00:05:24,450 --> 00:05:28,550 because, remember, pull is not asking for a value 130 00:05:28,550 --> 00:05:29,700 of type puller. 131 00:05:29,700 --> 00:05:33,150 It does not exist, there are no such things as type puller. 132 00:05:33,150 --> 00:05:35,100 It's saying, give me any piece of concrete data 133 00:05:35,100 --> 00:05:36,300 that knows how to pull. 134 00:05:36,300 --> 00:05:38,360 Store is not asking for a storer, 135 00:05:38,360 --> 00:05:41,017 any concrete piece of data that knows how to store. 136 00:05:41,017 --> 00:05:42,720 Here's the cool part. 137 00:05:42,720 --> 00:05:47,070 We're now passing PS to pull and PS to store 138 00:05:47,070 --> 00:05:48,770 because they don't exist, right. 139 00:05:48,770 --> 00:05:51,200 PS doesn't exist, get this in your head. 140 00:05:51,200 --> 00:05:53,560 PS is valueless, it doesn't exist. 141 00:05:53,560 --> 00:05:54,660 What exists? 142 00:05:54,660 --> 00:05:56,219 The concrete data. 143 00:05:56,219 --> 00:05:59,830 What we're really passing to pull is not PS. 144 00:05:59,830 --> 00:06:02,370 We're passing what is stored inside of PS, 145 00:06:02,370 --> 00:06:03,910 which is the concrete data. 146 00:06:03,910 --> 00:06:06,560 Which means that when we call pull, 147 00:06:06,560 --> 00:06:09,810 what we're able to do is pass the concrete data through. 148 00:06:09,810 --> 00:06:11,170 Look at what we've done. 149 00:06:11,170 --> 00:06:13,390 Now, the memory models are the same, 150 00:06:13,390 --> 00:06:16,270 but what's more important is, is I'm not passing PS, 151 00:06:16,270 --> 00:06:19,020 I'm passing the System address. 152 00:06:19,020 --> 00:06:21,570 Boom, and the same thing with Storer. 153 00:06:21,570 --> 00:06:25,850 I'm not passing PS, I'm passing the concrete data 154 00:06:25,850 --> 00:06:28,020 that was stored inside. 155 00:06:28,020 --> 00:06:30,220 Oh, so get this in your head. 156 00:06:30,220 --> 00:06:34,410 We're always moving and copying concrete data, 157 00:06:34,410 --> 00:06:37,360 whether that data is directly copied by you 158 00:06:37,360 --> 00:06:41,080 or it's being copied indirectly from the interface, 159 00:06:41,080 --> 00:06:44,380 the valueless interface, right, yeah, yeah. 160 00:06:44,380 --> 00:06:46,510 I mean, this interface now has a value, 161 00:06:46,510 --> 00:06:49,060 thanks to the storage of this concrete type. 162 00:06:49,060 --> 00:06:52,720 We're always moving the concrete type across the boundaries, 163 00:06:52,720 --> 00:06:53,553 and in this case, 164 00:06:53,553 --> 00:06:56,120 the data that we're moving is the address of System. 165 00:06:56,120 --> 00:06:57,520 That's why we're able to do this. 166 00:06:57,520 --> 00:07:00,630 Now we could call this implicit interface conversion, 167 00:07:00,630 --> 00:07:03,970 if you want, but I'd rather really focus on the idea 168 00:07:03,970 --> 00:07:06,360 that it's the concrete data that's being moved around, 169 00:07:06,360 --> 00:07:08,190 not the interface value. 170 00:07:08,190 --> 00:07:10,610 Again, the interface value is valueless. 171 00:07:10,610 --> 00:07:12,560 Now, we're not done yet, because I already said 172 00:07:12,560 --> 00:07:13,830 that we're going to have to decouple 173 00:07:13,830 --> 00:07:14,927 all the way through main. 174 00:07:14,927 --> 00:07:19,500 Then when our APIs are decoupled here, the reality is that, 175 00:07:19,500 --> 00:07:23,320 if I want to use Alice or Bob, I can't right now. 176 00:07:23,320 --> 00:07:25,943 We have this type, a concrete type called System. 177 00:07:26,940 --> 00:07:29,850 System is the embedding of Xenia and Pillar. 178 00:07:29,850 --> 00:07:31,980 If I want to use Bob or Alice, 179 00:07:31,980 --> 00:07:34,760 I either have to break System, which is not good, 180 00:07:34,760 --> 00:07:39,750 or maybe what I can do is to find another system type, 181 00:07:39,750 --> 00:07:41,470 maybe I can do this. 182 00:07:41,470 --> 00:07:42,440 Right? 183 00:07:42,440 --> 00:07:45,050 But think about this for a second. 184 00:07:45,050 --> 00:07:48,230 If I do this, if this is not scalable, 185 00:07:48,230 --> 00:07:52,120 System 2 is a PullStorer, I mean, this will work. 186 00:07:52,120 --> 00:07:54,810 But what happens for all the different combinations 187 00:07:54,810 --> 00:07:57,160 of Xenia, Pillar, Bob, Alice, all of that? 188 00:07:57,160 --> 00:07:58,300 This isn't scalable, 189 00:07:58,300 --> 00:08:01,180 this is really not the direction we want to go in. 190 00:08:01,180 --> 00:08:05,090 That being said, how can we solve this problem then? 191 00:08:05,090 --> 00:08:07,610 Well, let me ask you a question. 192 00:08:07,610 --> 00:08:11,540 If System wasn't the embedding of Xenia and Pillar, 193 00:08:11,540 --> 00:08:15,930 but the embedding of our two interface, 194 00:08:15,930 --> 00:08:20,250 if I can type this right, interface types. 195 00:08:20,250 --> 00:08:22,900 Whoa, what does this mean? 196 00:08:22,900 --> 00:08:24,000 Think about it. 197 00:08:24,000 --> 00:08:26,860 I have just defined a concrete type 198 00:08:26,860 --> 00:08:30,600 where I can inject other concrete data 199 00:08:30,600 --> 00:08:34,040 based on that data's behavior. 200 00:08:34,040 --> 00:08:39,040 Now, all I need is one system type, because the system, 201 00:08:39,070 --> 00:08:42,090 we can inject concrete data inside of it. 202 00:08:42,090 --> 00:08:45,100 Look, so how do we take this now and make these changes? 203 00:08:45,100 --> 00:08:47,150 Well, let's go in here and say this, 204 00:08:47,150 --> 00:08:52,020 a System now says Puller, and this is now Storer, 205 00:08:52,020 --> 00:08:53,960 and we've got to use our pointer semantics 206 00:08:53,960 --> 00:08:55,491 because we've implemented the interfaces 207 00:08:55,491 --> 00:08:57,110 with pointer semantics. 208 00:08:57,110 --> 00:08:59,200 Now look at what we've done. 209 00:08:59,200 --> 00:09:02,530 We're injecting Xenia, we're injecting Pillar. 210 00:09:02,530 --> 00:09:05,600 Later on, we can inject Bob if we want. 211 00:09:05,600 --> 00:09:09,640 We can do that all through this one concrete type. 212 00:09:09,640 --> 00:09:12,080 Which means we can still pass System through 213 00:09:12,080 --> 00:09:13,530 and everything should work. 214 00:09:13,530 --> 00:09:15,370 Let's see, if I did, there it is. 215 00:09:15,370 --> 00:09:16,203 Look at that. 216 00:09:16,203 --> 00:09:20,390 We're now able to inject data into our concrete type 217 00:09:20,390 --> 00:09:23,130 and we have a full layer of decoupling, 218 00:09:23,130 --> 00:09:25,930 we can define a system to be almost anything 219 00:09:25,930 --> 00:09:27,340 as long as the other concrete data 220 00:09:27,340 --> 00:09:29,470 implements the right behavior. 221 00:09:29,470 --> 00:09:30,640 Now, it's very important to me, 222 00:09:30,640 --> 00:09:32,520 after we get a piece of code working, 223 00:09:32,520 --> 00:09:35,040 that we do a code readability review. 224 00:09:35,040 --> 00:09:36,730 Code readability reviews are critical. 225 00:09:36,730 --> 00:09:38,330 There's really two types of code reviews 226 00:09:38,330 --> 00:09:39,440 you should be doing. 227 00:09:39,440 --> 00:09:41,340 There is the readability review, 228 00:09:41,340 --> 00:09:42,210 and you should be doing this 229 00:09:42,210 --> 00:09:44,630 every single time you get a piece of code working. 230 00:09:44,630 --> 00:09:46,820 The readability review there is to make sure 231 00:09:46,820 --> 00:09:49,360 that we're consistent with our variables, 232 00:09:49,360 --> 00:09:52,260 with our API designs, with our semantics. 233 00:09:52,260 --> 00:09:54,100 These things must be in place, right? 234 00:09:54,100 --> 00:09:56,240 We want to make sure that our mental models 235 00:09:56,240 --> 00:09:58,220 of our code is always in place. 236 00:09:58,220 --> 00:10:01,030 Treat the readability review as a way 237 00:10:01,030 --> 00:10:04,680 of validating our mental models of every function, 238 00:10:04,680 --> 00:10:08,120 every method, the location of things, the namings of things. 239 00:10:08,120 --> 00:10:10,070 Then the next review after that is going to be 240 00:10:10,070 --> 00:10:12,070 more of our technical review. 241 00:10:12,070 --> 00:10:14,020 There we could also look at API design, 242 00:10:14,020 --> 00:10:15,990 we could look at algorithm efficiencies, 243 00:10:15,990 --> 00:10:18,530 we can look at things that maybe we want to improve. 244 00:10:18,530 --> 00:10:20,950 But the code readability review is critical. 245 00:10:20,950 --> 00:10:22,760 When I start doing a code readability review, 246 00:10:22,760 --> 00:10:24,690 I realized one thing here. 247 00:10:24,690 --> 00:10:27,070 I'm never going to have more than one System type. 248 00:10:27,070 --> 00:10:29,510 The System type, thanks to the embedding of the interface, 249 00:10:29,510 --> 00:10:31,690 is already fully decoupled. 250 00:10:31,690 --> 00:10:34,690 Since I'm not going to have more than one System type, 251 00:10:34,690 --> 00:10:37,780 this interface is now pollution. 252 00:10:37,780 --> 00:10:41,684 Look, I can go back and work in the concrete, 253 00:10:41,684 --> 00:10:45,860 because I'm never going to have a second implementation 254 00:10:45,860 --> 00:10:47,200 of PullStorer. 255 00:10:47,200 --> 00:10:50,000 Having it there is a waste of time. 256 00:10:50,000 --> 00:10:53,500 I can now go back and use our concrete type, 257 00:10:53,500 --> 00:10:58,500 which means that I can go ahead and remove code. 258 00:10:58,650 --> 00:11:02,230 Oh, it's a great day when you can do something like this. 259 00:11:02,230 --> 00:11:04,580 There it is, I can remove this code. 260 00:11:04,580 --> 00:11:08,330 I change my higher level API back to the concrete type, 261 00:11:08,330 --> 00:11:09,450 passing System. 262 00:11:09,450 --> 00:11:12,090 This code works and I'm still at the highest level 263 00:11:12,090 --> 00:11:15,050 of decoupling that I can achieve in this program 264 00:11:15,050 --> 00:11:18,080 because of the data injection. 265 00:11:18,080 --> 00:11:20,890 Now, I do another code readability review, 266 00:11:20,890 --> 00:11:22,990 and I realize something else. 267 00:11:22,990 --> 00:11:26,295 This idea of data injection is super cool. 268 00:11:26,295 --> 00:11:27,510 But guess what? 269 00:11:27,510 --> 00:11:28,343 It's clever. 270 00:11:28,343 --> 00:11:33,230 Because this API isn't as precise as it could be. 271 00:11:33,230 --> 00:11:37,997 I mean, honestly, wouldn't this be a more precise API? 272 00:11:40,500 --> 00:11:41,373 Look at this. 273 00:11:42,910 --> 00:11:45,610 Think about this for a second. 274 00:11:45,610 --> 00:11:49,900 Wouldn't this be a more precise API? 275 00:11:49,900 --> 00:11:54,230 I mean, System is really hiding the cost of initialization. 276 00:11:54,230 --> 00:11:57,180 We don't really know what a System is when we look at Copy. 277 00:11:57,180 --> 00:11:59,410 We don't realize we need these two behaviors, 278 00:11:59,410 --> 00:12:01,480 at least somebody new to the code base. 279 00:12:01,480 --> 00:12:04,030 But now with this new API definition 280 00:12:04,030 --> 00:12:06,910 we've reduced fraud, we're going to make this API 281 00:12:06,910 --> 00:12:11,910 easier to use, easier to test, because it's exactly saying, 282 00:12:11,940 --> 00:12:13,710 give me concrete data that implements Puller, 283 00:12:13,710 --> 00:12:15,470 give me concrete data that implements Storer. 284 00:12:15,470 --> 00:12:18,880 We know exactly what Copy needs and what it does 285 00:12:18,880 --> 00:12:23,180 and much more than when we use this idea of a system. 286 00:12:23,180 --> 00:12:28,120 Again, I want to be as precise as we can be. 287 00:12:28,120 --> 00:12:32,110 Now, if we replace our API design to use puller and storer, 288 00:12:32,110 --> 00:12:34,860 now what we're going to do is pass our Puller, 289 00:12:34,860 --> 00:12:37,820 pass our Storer, that will fix that problem. 290 00:12:37,820 --> 00:12:39,810 Even main cleans up, 291 00:12:39,810 --> 00:12:42,750 because if you really think about it now, 292 00:12:42,750 --> 00:12:47,750 we can go back and just construct the concrete type. 293 00:12:47,990 --> 00:12:52,160 The concept of the interface is completely 294 00:12:52,160 --> 00:12:55,870 gone from initialization, let's clean this up, 295 00:12:55,870 --> 00:12:57,350 let's get rid of this. 296 00:12:57,350 --> 00:13:00,750 We're going to use the special Go func to clean that up. 297 00:13:00,750 --> 00:13:03,690 Now what we're going to do is share Xenia 298 00:13:03,690 --> 00:13:06,310 and share Pillar with Copy, 299 00:13:06,310 --> 00:13:11,130 and even our main program here has cleaned up tremendously 300 00:13:11,130 --> 00:13:13,400 because we're focused, again, on what's important, 301 00:13:13,400 --> 00:13:14,233 which is what? 302 00:13:14,233 --> 00:13:15,300 The concrete. 303 00:13:15,300 --> 00:13:17,450 Right here, during initialization, 304 00:13:17,450 --> 00:13:18,930 we focus on the concrete data, 305 00:13:18,930 --> 00:13:21,260 Xenia and Pillar are the problem. 306 00:13:21,260 --> 00:13:25,530 We pass Xenia and Pillar into Copy, a higher level API, 307 00:13:25,530 --> 00:13:28,550 our higher API is already decoupled now. 308 00:13:28,550 --> 00:13:30,070 Give me anything that implements Puller, 309 00:13:30,070 --> 00:13:33,080 anything that implements Storer, and we now have decoupling 310 00:13:33,080 --> 00:13:35,170 throughout the entire application. 311 00:13:35,170 --> 00:13:38,420 We've got an API now that really is going to limit 312 00:13:38,420 --> 00:13:42,410 and almost reduce all misuse and fraud for this software. 313 00:13:42,410 --> 00:13:44,870 Notice that this was a refactoring, 314 00:13:44,870 --> 00:13:46,430 and I don't want you to be afraid of refactoring. 315 00:13:46,430 --> 00:13:48,300 If you're not refactoring, you're not improving. 316 00:13:48,300 --> 00:13:49,170 If you're not refactoring, 317 00:13:49,170 --> 00:13:50,800 I think you're doing things wrong. 318 00:13:50,800 --> 00:13:53,060 Look at the approach we took here, 319 00:13:53,060 --> 00:13:57,660 layering the API, validating every layer was testable, 320 00:13:57,660 --> 00:14:00,510 and we're thinking about tests from a data point of view, 321 00:14:00,510 --> 00:14:02,218 not from a decoupling point of view. 322 00:14:02,218 --> 00:14:05,467 I don't want hear, "Oh Bill, we've got to write tests, 323 00:14:05,467 --> 00:14:06,677 "and we've got to decouple code, 324 00:14:06,677 --> 00:14:07,747 "because we got to write tests. 325 00:14:07,747 --> 00:14:09,100 "Let's throw an interface at it." 326 00:14:09,100 --> 00:14:11,060 No, no, no, no, no, no, no, no, no. 327 00:14:11,060 --> 00:14:13,920 Layering, testing through data, 328 00:14:13,920 --> 00:14:15,560 building on top of each other, 329 00:14:15,560 --> 00:14:17,720 implementing a concrete solution first, 330 00:14:17,720 --> 00:14:19,770 and then asking, what needs to be decoupled 331 00:14:19,770 --> 00:14:21,120 and decoupling the program 332 00:14:21,120 --> 00:14:22,910 through more layers of refactoring 333 00:14:22,910 --> 00:14:25,050 and then doing code readability reviews 334 00:14:25,050 --> 00:14:28,570 to tighten up these APIs and asking ourselves, 335 00:14:28,570 --> 00:14:30,820 where is there potential fraud and misuse, 336 00:14:30,820 --> 00:14:32,390 where can we be more precise 337 00:14:32,390 --> 00:14:34,050 that we know the problem a little bit better 338 00:14:34,050 --> 00:14:36,053 and then putting those changes in.