1 00:00:06,580 --> 00:00:08,780 - Behavior as context allows us now 2 00:00:08,780 --> 00:00:10,510 to use these custom error types, 3 00:00:10,510 --> 00:00:12,270 but to stay decoupled. 4 00:00:12,270 --> 00:00:13,450 Let me show you that. 5 00:00:13,450 --> 00:00:16,510 Let's start again with our type as context example. 6 00:00:16,510 --> 00:00:19,600 Here in this function right here, this method, 7 00:00:19,600 --> 00:00:22,370 I am making a call to read string 8 00:00:22,370 --> 00:00:24,960 based on this interface value called reader. 9 00:00:24,960 --> 00:00:27,740 We can imagine that we've abstracted a network call. 10 00:00:27,740 --> 00:00:29,300 And when we make this call over the network, 11 00:00:29,300 --> 00:00:31,170 we should get a line of data back 12 00:00:31,170 --> 00:00:32,580 or we might get an error. 13 00:00:32,580 --> 00:00:34,730 So we check to see if there's a concrete value 14 00:00:34,730 --> 00:00:36,270 stored inside the error interface, 15 00:00:36,270 --> 00:00:38,770 and if there is, notice what I'm doing here. 16 00:00:38,770 --> 00:00:41,550 I'm doing a type as context, 17 00:00:41,550 --> 00:00:43,870 and I'm checking the different types 18 00:00:43,870 --> 00:00:47,430 of concrete error values that we have in the net package. 19 00:00:47,430 --> 00:00:50,300 Pointers to OpError, pointer to address error, 20 00:00:50,300 --> 00:00:52,310 pointer to DNSConfigError. 21 00:00:52,310 --> 00:00:55,010 There's types, lots of types of errors 22 00:00:55,010 --> 00:00:55,920 that can occur in the network, 23 00:00:55,920 --> 00:00:58,360 and the net package tries to cover them all. 24 00:00:58,360 --> 00:01:01,040 So this type of context looks pretty cool, 25 00:01:01,040 --> 00:01:03,580 because I can now filter down 26 00:01:03,580 --> 00:01:06,260 based on what was stored inside of the error interface 27 00:01:06,260 --> 00:01:08,940 on that call, which error we got. 28 00:01:08,940 --> 00:01:10,870 And you can see that I'm calling temporary 29 00:01:10,870 --> 00:01:12,870 on every one of these concrete values 30 00:01:12,870 --> 00:01:15,590 because you're told that if there's 31 00:01:15,590 --> 00:01:17,520 a temporary method like this, you should call it. 32 00:01:17,520 --> 00:01:19,840 Remember, errors are just values in Go. 33 00:01:19,840 --> 00:01:21,510 They can be anything we need them to be, 34 00:01:21,510 --> 00:01:23,390 both in state and behavior. 35 00:01:23,390 --> 00:01:25,230 This temporary method is beautiful, 36 00:01:25,230 --> 00:01:27,520 because if it's temporary, then we know 37 00:01:27,520 --> 00:01:31,600 that we're still in a state of integrity, just keep going. 38 00:01:31,600 --> 00:01:35,510 If it's not, if it's not temporary, we've lost integrity. 39 00:01:35,510 --> 00:01:38,310 Maybe that listener has gone down, that socket has dropped. 40 00:01:38,310 --> 00:01:40,930 And now we have to make sure that we can recover. 41 00:01:40,930 --> 00:01:43,200 Okay, this is great, but again we're moving 42 00:01:43,200 --> 00:01:46,410 from a decoupled to a coupled state. 43 00:01:46,410 --> 00:01:49,410 If we make any changes to these concrete types, 44 00:01:49,410 --> 00:01:50,710 this code's gonna break, 45 00:01:50,710 --> 00:01:52,930 especially something from a net package 46 00:01:52,930 --> 00:01:54,970 where lots of applications 47 00:01:54,970 --> 00:01:56,480 are dealing with networking today. 48 00:01:56,480 --> 00:01:59,120 This could create cascading changes 49 00:01:59,120 --> 00:02:01,500 across large, different code bases 50 00:02:01,500 --> 00:02:02,780 that we don't even own. 51 00:02:02,780 --> 00:02:05,500 Okay, so what we prefer to do 52 00:02:05,500 --> 00:02:07,948 is try to maintain this level of decoupling. 53 00:02:07,948 --> 00:02:11,420 Let me switch over to the net package for a second. 54 00:02:11,420 --> 00:02:14,220 We'll do a search golang/net, 55 00:02:14,220 --> 00:02:17,370 and I'm gonna see the net package come up here. 56 00:02:17,370 --> 00:02:20,640 And what I'm gonna do is search for OpError. 57 00:02:20,640 --> 00:02:21,760 I want to look at OpError. 58 00:02:21,760 --> 00:02:26,150 OpError is the most common type of concrete type 59 00:02:26,150 --> 00:02:29,020 we might be using for error handling in the net package. 60 00:02:29,020 --> 00:02:30,053 It's our most common error type. 61 00:02:30,053 --> 00:02:32,350 All right, I do want you to notice something 62 00:02:32,350 --> 00:02:33,890 that I didn't mention before. 63 00:02:33,890 --> 00:02:36,800 There is a naming convention for a custom error type. 64 00:02:36,800 --> 00:02:39,470 And that's that it ends in the word Error. 65 00:02:39,470 --> 00:02:43,136 And you'll see that in custom error types. 66 00:02:43,136 --> 00:02:47,030 OpError, you know, and we saw that also as well over here 67 00:02:47,030 --> 00:02:50,420 with address error, DNSConfigError. 68 00:02:50,420 --> 00:02:52,400 So that's a naming convention I want you to follow 69 00:02:52,400 --> 00:02:54,640 when you're defining a custom error type. 70 00:02:54,640 --> 00:02:57,340 Now I made all of this orange on that search, 71 00:02:57,340 --> 00:02:58,723 so we're on line 414. 72 00:02:59,880 --> 00:03:01,790 So let me just get rid of that. 73 00:03:01,790 --> 00:03:05,040 We'll go over to 414 so we can see it a little bit better. 74 00:03:05,040 --> 00:03:06,410 Now here we go. 75 00:03:06,410 --> 00:03:08,300 Here is the OpError type, 76 00:03:08,300 --> 00:03:10,120 and we'll try to bring it all into view. 77 00:03:10,120 --> 00:03:12,740 And you can see that this is a type 78 00:03:12,740 --> 00:03:16,390 that is exported with five exported fields. 79 00:03:16,390 --> 00:03:19,270 You're able to inspect all of the details 80 00:03:19,270 --> 00:03:20,700 you want from the networking error. 81 00:03:20,700 --> 00:03:23,310 The net package has exported everything. 82 00:03:23,310 --> 00:03:25,490 But if I scroll down, you're gonna notice 83 00:03:25,490 --> 00:03:29,520 that this is the implementation of the error interface. 84 00:03:29,520 --> 00:03:32,050 Look at that, it's using pointer semantics 85 00:03:32,050 --> 00:03:34,040 for the implementation, not a surprise. 86 00:03:34,040 --> 00:03:36,040 You can also see how complex it is. 87 00:03:36,040 --> 00:03:37,730 The string is gonna be very complex. 88 00:03:37,730 --> 00:03:39,920 Again, we don't want to have to parse this string 89 00:03:39,920 --> 00:03:42,000 to figure out what's going on. 90 00:03:42,000 --> 00:03:46,450 Now all of those types will have this error implementation 91 00:03:46,450 --> 00:03:48,050 using the pointer semantics, 92 00:03:48,050 --> 00:03:49,610 but what I want to focus on next 93 00:03:49,610 --> 00:03:51,650 is the temporary method. 94 00:03:51,650 --> 00:03:56,280 Let's see if we can find the temporary method for OpError. 95 00:03:56,280 --> 00:03:58,020 Oh, look, there it is. 96 00:03:58,020 --> 00:04:00,180 Look how complex this method is. 97 00:04:00,180 --> 00:04:03,330 Thank God they implemented this, 98 00:04:03,330 --> 00:04:07,040 because look at all of the type assertions. 99 00:04:07,040 --> 00:04:09,460 I mean, I wouldn't have been able to figure this out. 100 00:04:09,460 --> 00:04:12,260 So this temporary method returning to a fault 101 00:04:12,260 --> 00:04:15,400 is brilliant, and it's really, really important, 102 00:04:15,400 --> 00:04:17,390 because it's gonna allow us to simplify 103 00:04:17,390 --> 00:04:20,870 whether or not there is or is not an integrity issue 104 00:04:20,870 --> 00:04:24,290 or something as complex as a networking issue. 105 00:04:24,290 --> 00:04:26,450 But I want us to go back to this code for a second, 106 00:04:26,450 --> 00:04:29,000 because if we go back here, 107 00:04:29,000 --> 00:04:30,850 you should see this pattern 108 00:04:30,850 --> 00:04:32,040 where we're type asserting 109 00:04:32,040 --> 00:04:34,490 to the concrete to call temporary, 110 00:04:34,490 --> 00:04:36,980 type asserting to the concrete to call temporary, 111 00:04:36,980 --> 00:04:38,330 to call temporary. 112 00:04:38,330 --> 00:04:41,540 Really, the common behavior here is temporary. 113 00:04:41,540 --> 00:04:43,060 This is all I care about. 114 00:04:43,060 --> 00:04:45,860 Technically, I almost don't even care 115 00:04:45,860 --> 00:04:49,760 what the concrete type is if there's a temporary method. 116 00:04:49,760 --> 00:04:54,300 So let's apply the ideas of behavior as context 117 00:04:54,300 --> 00:04:56,260 and clean up this code. 118 00:04:56,260 --> 00:04:58,956 We can start off with the idea of this, 119 00:04:58,956 --> 00:05:01,575 let's take a look at this. 120 00:05:01,575 --> 00:05:02,760 Look at this code here. 121 00:05:02,760 --> 00:05:05,070 This becomes very interesting to me. 122 00:05:05,070 --> 00:05:10,070 Look how the net package has an interface called temporary. 123 00:05:10,420 --> 00:05:13,040 They have inside this code base 124 00:05:13,040 --> 00:05:15,530 defined a level of decoupling 125 00:05:15,530 --> 00:05:17,900 through this temporary behavior. 126 00:05:17,900 --> 00:05:21,490 But also notice that it's unexported. 127 00:05:21,490 --> 00:05:22,323 What does that mean? 128 00:05:22,323 --> 00:05:23,310 It means that we don't have access 129 00:05:23,310 --> 00:05:26,170 to this interface type from our code. 130 00:05:26,170 --> 00:05:28,070 But it would have been nice to have access to it, 131 00:05:28,070 --> 00:05:31,380 because we could have leveraged it for our own decoupling. 132 00:05:31,380 --> 00:05:33,400 But guess what, it would have been a mistake 133 00:05:33,400 --> 00:05:34,630 to have this exported, 134 00:05:34,630 --> 00:05:36,300 because the only piece of code 135 00:05:36,300 --> 00:05:37,890 that needs to implement temporary 136 00:05:37,890 --> 00:05:39,690 is inside the net package. 137 00:05:39,690 --> 00:05:42,220 They own the different custom error types. 138 00:05:42,220 --> 00:05:44,550 They have the need to be coupled. 139 00:05:44,550 --> 00:05:46,440 We're not implementing temporary 140 00:05:46,440 --> 00:05:48,020 on behalf of the net package. 141 00:05:48,020 --> 00:05:49,640 It's for internal use. 142 00:05:49,640 --> 00:05:51,070 So you remember that Go's 143 00:05:51,070 --> 00:05:53,460 about convention over configuration. 144 00:05:53,460 --> 00:05:57,470 There's nothing stopping us from defining 145 00:05:57,470 --> 00:06:00,010 our own temporary interface, is there? 146 00:06:00,010 --> 00:06:02,860 No, and isn't it true that any concrete type 147 00:06:02,860 --> 00:06:05,720 that has the temporary method inside the net package 148 00:06:05,720 --> 00:06:09,770 also implements or satisfies our temporary interface? 149 00:06:09,770 --> 00:06:11,700 It absolutely does. 150 00:06:11,700 --> 00:06:15,630 Again, the beauty of Go is static code analysis, right? 151 00:06:15,630 --> 00:06:18,740 The beauty of Go, convention over configuration, 152 00:06:18,740 --> 00:06:21,570 is we now implement our own interface 153 00:06:21,570 --> 00:06:24,440 that the concrete values inside the net package 154 00:06:24,440 --> 00:06:26,730 also implement, right, that data, 155 00:06:26,730 --> 00:06:28,270 the values and the pointers. 156 00:06:28,270 --> 00:06:29,600 So look at what I do. 157 00:06:29,600 --> 00:06:33,260 We're gonna go from these three cases, right, 158 00:06:33,260 --> 00:06:35,130 the three cases on the error 159 00:06:35,130 --> 00:06:37,396 where we're going from decoupling 160 00:06:37,396 --> 00:06:39,410 to that concrete, 161 00:06:39,410 --> 00:06:42,920 and I'm gonna move it all down into one case. 162 00:06:42,920 --> 00:06:43,870 There it is. 163 00:06:43,870 --> 00:06:46,070 This time when we do the type assertion, 164 00:06:46,070 --> 00:06:47,046 I'm not gonna ask 165 00:06:47,046 --> 00:06:50,690 what the concrete data is inside of E. 166 00:06:50,690 --> 00:06:53,786 What I'm gonna ask is does that concrete data 167 00:06:53,786 --> 00:06:57,680 also implement my temporary interface? 168 00:06:57,680 --> 00:07:00,990 I am now staying within a decoupled state. 169 00:07:00,990 --> 00:07:02,810 And when I do that now, 170 00:07:02,810 --> 00:07:05,710 I go to just one case, that's it. 171 00:07:05,710 --> 00:07:07,770 I don't care what the concrete data is. 172 00:07:07,770 --> 00:07:10,320 All I care about is that it implements temporary. 173 00:07:10,320 --> 00:07:12,570 And temporary will tell me whether or not 174 00:07:12,570 --> 00:07:13,720 I have an integrity issue. 175 00:07:13,720 --> 00:07:16,240 This is beautiful, right? 176 00:07:16,240 --> 00:07:19,415 The fact that an error value can have not just state 177 00:07:19,415 --> 00:07:23,290 but behavior, can allow your call or your user 178 00:07:23,290 --> 00:07:26,270 to maintain decoupling in error handling, 179 00:07:26,270 --> 00:07:30,230 even when we're using these custom error types. 180 00:07:30,230 --> 00:07:33,175 So here's a general rule that I want you to follow. 181 00:07:33,175 --> 00:07:36,170 If your custom error type can have 182 00:07:36,170 --> 00:07:38,110 any one of these four methods, 183 00:07:38,110 --> 00:07:39,470 it doesn't have to have all of them, 184 00:07:39,470 --> 00:07:42,720 just one, then I want the custom error type 185 00:07:42,720 --> 00:07:47,430 to be defined as unexported with unexported fields, 186 00:07:47,430 --> 00:07:50,346 because if it's unexported with unexported fields, 187 00:07:50,346 --> 00:07:54,830 you're forcing that your user can never, ever go 188 00:07:54,830 --> 00:07:57,390 from a decoupled state to that concrete, right? 189 00:07:57,390 --> 00:07:59,460 We can't type assert to the concrete. 190 00:07:59,460 --> 00:08:00,720 You're really helping them out, 191 00:08:00,720 --> 00:08:03,210 even though they might feel like they're being restricted. 192 00:08:03,210 --> 00:08:05,680 Here are the four methods, okay? 193 00:08:05,680 --> 00:08:09,080 Temporary, time out, not found, 194 00:08:09,080 --> 00:08:11,230 and not authorized, that's it. 195 00:08:11,230 --> 00:08:13,020 There isn't really another one. 196 00:08:13,020 --> 00:08:15,210 If you can add any one of these four, 197 00:08:15,210 --> 00:08:19,010 we can maintain decoupling with custom error types 198 00:08:19,010 --> 00:08:21,720 by making the custom error type unexported. 199 00:08:21,720 --> 00:08:24,900 Remember, temporary covers a tremendous amount. 200 00:08:24,900 --> 00:08:28,220 Temporary is really kind of this blanket statement 201 00:08:28,220 --> 00:08:31,350 that you have an integrity issue or you don't. 202 00:08:31,350 --> 00:08:32,770 And if people have complained 203 00:08:32,770 --> 00:08:35,630 that you've made the custom error type unexported 204 00:08:35,630 --> 00:08:37,820 and you have a valid temporary method, 205 00:08:37,820 --> 00:08:40,980 just tell them, look, we're not going to export the type, 206 00:08:40,980 --> 00:08:42,580 even if you feel like you need 207 00:08:42,580 --> 00:08:45,410 to inspect it directly yourself. 208 00:08:45,410 --> 00:08:48,360 Let's fix temporary to be more accurate. 209 00:08:48,360 --> 00:08:49,330 Where it's brilliant is 210 00:08:49,330 --> 00:08:51,630 we can fix temporary to be more accurate 211 00:08:51,630 --> 00:08:54,050 without creating a cascading code change, 212 00:08:54,050 --> 00:08:55,480 because this code doesn't change 213 00:08:55,480 --> 00:08:57,640 if we change the implementation of temporary. 214 00:08:57,640 --> 00:08:59,670 If anything, this code gets better 215 00:08:59,670 --> 00:09:01,730 because it's more accurate. 216 00:09:01,730 --> 00:09:03,610 Now if you have a custom error type 217 00:09:03,610 --> 00:09:05,460 like the JSON package did, 218 00:09:05,460 --> 00:09:06,733 you remember those custom error types 219 00:09:06,733 --> 00:09:09,754 that we talked about before for the JSON package, 220 00:09:09,754 --> 00:09:13,200 time out, temporary, not found, not authorized. 221 00:09:13,200 --> 00:09:15,250 They don't work for those types. 222 00:09:15,250 --> 00:09:17,300 Those types have to be exported. 223 00:09:17,300 --> 00:09:19,840 The user may need to move 224 00:09:19,840 --> 00:09:21,820 from decoupling back to the concrete. 225 00:09:21,820 --> 00:09:25,130 It's a scary situation, but that is what it is. 226 00:09:25,130 --> 00:09:27,084 Most of the time, that temporary method 227 00:09:27,084 --> 00:09:29,230 is going to work for you. 228 00:09:29,230 --> 00:09:31,890 So I don't have a problem with the custom error types 229 00:09:31,890 --> 00:09:34,290 as soon as the error variables don't work, 230 00:09:34,290 --> 00:09:36,660 but I'd love to make sure that those custom error types 231 00:09:36,660 --> 00:09:38,490 are unexported with unexported fields, 232 00:09:38,490 --> 00:09:42,600 and that we apply method sets of behavior 233 00:09:42,600 --> 00:09:45,310 that the user can bind to 234 00:09:45,310 --> 00:09:47,080 to maintain that their error handling 235 00:09:47,080 --> 00:09:49,423 is done from a decoupling state.