1 00:00:00,480 --> 00:00:03,480 foreign 2 00:00:08,639 --> 00:00:13,440 it's my pleasure to introduce Evan Evan 3 00:00:11,519 --> 00:00:15,599 is a software engineer whose passions 4 00:00:13,440 --> 00:00:17,400 lie in improving the developer 5 00:00:15,599 --> 00:00:19,619 experience by reducing human error 6 00:00:17,400 --> 00:00:21,600 enhancing code health and optimizing 7 00:00:19,619 --> 00:00:23,580 workflows when he's not thinking about 8 00:00:21,600 --> 00:00:25,740 security informatics or giving talks 9 00:00:23,580 --> 00:00:27,720 about as many projects you'll find him 10 00:00:25,740 --> 00:00:30,900 numbing on subway cookies or chasing 11 00:00:27,720 --> 00:00:33,920 bunny rabbits please put your uh an 12 00:00:30,900 --> 00:00:33,920 Applause for Evan 13 00:00:37,200 --> 00:00:42,899 thank you 14 00:00:39,960 --> 00:00:45,180 um cool hello everyone and welcome to my 15 00:00:42,899 --> 00:00:48,600 story about refactoring 16 00:00:45,180 --> 00:00:50,399 but what is refactoring well it's the 17 00:00:48,600 --> 00:00:51,660 process of improving horrendous code 18 00:00:50,399 --> 00:00:54,539 like this 19 00:00:51,660 --> 00:00:57,960 to a beautiful code like this 20 00:00:54,539 --> 00:01:00,539 all while ensuring that code still runs 21 00:00:57,960 --> 00:01:02,879 tests still pass functionality is kept 22 00:01:00,539 --> 00:01:04,500 the same and the user doesn't suspect 23 00:01:02,879 --> 00:01:06,799 the thing 24 00:01:04,500 --> 00:01:08,939 this could be done by doing things like 25 00:01:06,799 --> 00:01:11,159 changing formatting 26 00:01:08,939 --> 00:01:13,439 renaming variables 27 00:01:11,159 --> 00:01:15,540 updating the structure 28 00:01:13,439 --> 00:01:17,640 or using different algorithms and 29 00:01:15,540 --> 00:01:19,500 tick-tactic sugar 30 00:01:17,640 --> 00:01:21,540 and today I'll be talking about the 31 00:01:19,500 --> 00:01:24,479 story of refactoring a side project of 32 00:01:21,540 --> 00:01:27,360 mine that solves annotates and validates 33 00:01:24,479 --> 00:01:31,259 the minimum Paths of this train game 34 00:01:27,360 --> 00:01:33,540 well I'm such a nerd um anyways why am I 35 00:01:31,259 --> 00:01:36,119 refactoring it well 36 00:01:33,540 --> 00:01:37,560 I was a bit stuck and I wanted some help 37 00:01:36,119 --> 00:01:40,500 from others 38 00:01:37,560 --> 00:01:42,659 not only that but it was hard for me to 39 00:01:40,500 --> 00:01:44,640 easily make changes and if it was hard 40 00:01:42,659 --> 00:01:47,640 for me to understand well it would have 41 00:01:44,640 --> 00:01:51,600 been even harder for someone else 42 00:01:47,640 --> 00:01:54,000 okay so how did I get here 43 00:01:51,600 --> 00:01:55,259 well often I have an idea that I want to 44 00:01:54,000 --> 00:01:57,360 implement 45 00:01:55,259 --> 00:01:59,100 and python is a great choice for doing 46 00:01:57,360 --> 00:02:02,700 so quickly 47 00:01:59,100 --> 00:02:04,439 but as I added code and more code and 48 00:02:02,700 --> 00:02:06,780 more code 49 00:02:04,439 --> 00:02:08,520 it quickly turns from a small script to 50 00:02:06,780 --> 00:02:10,020 an unmaintainable project 51 00:02:08,520 --> 00:02:12,599 do you want to see 52 00:02:10,020 --> 00:02:14,459 no I I won't get you to read the entire 53 00:02:12,599 --> 00:02:16,200 code because you don't have to 54 00:02:14,459 --> 00:02:18,660 in the same way that you can often just 55 00:02:16,200 --> 00:02:20,400 skim an entire article to get an idea of 56 00:02:18,660 --> 00:02:23,340 what it's about 57 00:02:20,400 --> 00:02:25,160 like if we skim through this code 58 00:02:23,340 --> 00:02:27,840 uh 59 00:02:25,160 --> 00:02:29,580 you see that uh 60 00:02:27,840 --> 00:02:32,400 could you say that you have a reasonable 61 00:02:29,580 --> 00:02:35,700 idea of what it does where to start 62 00:02:32,400 --> 00:02:37,860 what it's made of what's important how 63 00:02:35,700 --> 00:02:40,940 it works 64 00:02:37,860 --> 00:02:40,940 it's quite long 65 00:02:41,640 --> 00:02:45,480 um 66 00:02:42,540 --> 00:02:48,239 yeah my answer to that is no 67 00:02:45,480 --> 00:02:50,700 um but when I look at where I'm at now I 68 00:02:48,239 --> 00:02:52,620 can easily Hazard that the project has 69 00:02:50,700 --> 00:02:55,620 something to do with graphs and 70 00:02:52,620 --> 00:02:57,800 annotations and mapping and stats and so 71 00:02:55,620 --> 00:02:57,800 on 72 00:02:57,959 --> 00:03:04,080 why was it so messy how did it become 73 00:03:00,900 --> 00:03:06,180 like this well because no one is perfect 74 00:03:04,080 --> 00:03:09,060 and can know what all the future 75 00:03:06,180 --> 00:03:11,099 requirements will be or know all the 76 00:03:09,060 --> 00:03:14,220 syntactic sugar of a language 77 00:03:11,099 --> 00:03:16,379 or no identify when to use design 78 00:03:14,220 --> 00:03:18,239 principles and patterns 79 00:03:16,379 --> 00:03:20,280 or have the time to make all these 80 00:03:18,239 --> 00:03:22,560 changes up front since with any piece of 81 00:03:20,280 --> 00:03:24,659 code you can try your best to avoid 82 00:03:22,560 --> 00:03:26,159 these problems by having an idea for 83 00:03:24,659 --> 00:03:29,220 what to look out for 84 00:03:26,159 --> 00:03:31,500 but you need to stop step back and take 85 00:03:29,220 --> 00:03:35,819 a look at what you're doing 86 00:03:31,500 --> 00:03:38,159 okay so if we do that what can we do 87 00:03:35,819 --> 00:03:39,599 well the first and easiest step is to 88 00:03:38,159 --> 00:03:42,720 use a formatter 89 00:03:39,599 --> 00:03:44,459 it lets us take messy long condensed and 90 00:03:42,720 --> 00:03:46,980 inconsistently written blocks like this 91 00:03:44,459 --> 00:03:47,780 which you can see are gone off the 92 00:03:46,980 --> 00:03:50,099 screen 93 00:03:47,780 --> 00:03:53,099 and automatically turn them into this 94 00:03:50,099 --> 00:03:55,379 which is much more human readable 95 00:03:53,099 --> 00:03:57,120 and even if I blur the example to 96 00:03:55,379 --> 00:03:59,940 simulate skimming it 97 00:03:57,120 --> 00:04:01,700 it's probably a lot easier to tell that 98 00:03:59,940 --> 00:04:04,440 the formatted case we're actually 99 00:04:01,700 --> 00:04:06,599 filtering a list 100 00:04:04,440 --> 00:04:08,159 now in terms of formatters there's a 101 00:04:06,599 --> 00:04:10,560 couple you can choose from so you can 102 00:04:08,159 --> 00:04:13,019 spend a couple of hours researching each 103 00:04:10,560 --> 00:04:15,959 one taking a look at what they do 104 00:04:13,019 --> 00:04:18,000 no wait why do you really want to do 105 00:04:15,959 --> 00:04:19,560 that I mean if your goal is to learn 106 00:04:18,000 --> 00:04:21,900 sure 107 00:04:19,560 --> 00:04:23,940 but a good methodology to take away here 108 00:04:21,900 --> 00:04:25,320 right from the beginning is one about 109 00:04:23,940 --> 00:04:27,240 pragmatism 110 00:04:25,320 --> 00:04:29,160 because one of the biggest qualms of 111 00:04:27,240 --> 00:04:30,360 refactoring is the amount of time it can 112 00:04:29,160 --> 00:04:32,400 take 113 00:04:30,360 --> 00:04:33,540 it's important to realize when something 114 00:04:32,400 --> 00:04:35,880 is good enough 115 00:04:33,540 --> 00:04:37,800 so if you're trying to be pragmatic just 116 00:04:35,880 --> 00:04:40,139 pick the first thing you find 117 00:04:37,800 --> 00:04:42,300 I chose to use black it's opinionated 118 00:04:40,139 --> 00:04:43,979 but that doesn't matter to me all that 119 00:04:42,300 --> 00:04:46,080 matters is that my code is always 120 00:04:43,979 --> 00:04:48,600 formatted to be readable and consistent 121 00:04:46,080 --> 00:04:50,699 because in future trusting the formatter 122 00:04:48,600 --> 00:04:52,560 to automatically fix things and not 123 00:04:50,699 --> 00:04:54,780 having to debate with myself or others 124 00:04:52,560 --> 00:04:58,139 is what will save time 125 00:04:54,780 --> 00:05:00,240 and if I do find issues then it's very 126 00:04:58,139 --> 00:05:03,540 easy to swap out later because you can 127 00:05:00,240 --> 00:05:06,120 just reformat all my code at once again 128 00:05:03,540 --> 00:05:08,460 but even formatted code can still have 129 00:05:06,120 --> 00:05:11,220 issues format is going to tell you about 130 00:05:08,460 --> 00:05:13,800 code smells like problematic naming and 131 00:05:11,220 --> 00:05:16,080 like single characters spelling mistakes 132 00:05:13,800 --> 00:05:19,500 like Celsius and Fahrenheit 133 00:05:16,080 --> 00:05:22,139 unused code like this last line 134 00:05:19,500 --> 00:05:24,720 or duplicated code 135 00:05:22,139 --> 00:05:26,460 but I'll enter like rough wheel lenses 136 00:05:24,720 --> 00:05:28,860 are great because they can look at all 137 00:05:26,460 --> 00:05:30,720 your code as you write it and raise 138 00:05:28,860 --> 00:05:31,979 issues for fixing that you might not be 139 00:05:30,720 --> 00:05:34,320 aware of 140 00:05:31,979 --> 00:05:35,580 there's a whole list of them and you 141 00:05:34,320 --> 00:05:37,259 don't even have to follow all of them 142 00:05:35,580 --> 00:05:39,060 you can silence the ones you don't like 143 00:05:37,259 --> 00:05:40,860 or make your own 144 00:05:39,060 --> 00:05:42,780 but they'll often guide you into good 145 00:05:40,860 --> 00:05:44,460 patterns that you might otherwise have 146 00:05:42,780 --> 00:05:46,259 not considered 147 00:05:44,460 --> 00:05:48,479 like this morning I got about my 148 00:05:46,259 --> 00:05:51,360 function have too many arguments 149 00:05:48,479 --> 00:05:53,460 first it made me think that's silly what 150 00:05:51,360 --> 00:05:55,800 what's wrong with that 151 00:05:53,460 --> 00:05:57,780 but when I took a step back and thought 152 00:05:55,800 --> 00:06:00,660 about how to address it it made me 153 00:05:57,780 --> 00:06:02,580 realize there was a better way 154 00:06:00,660 --> 00:06:04,560 if we took a look at the beginning we'll 155 00:06:02,580 --> 00:06:06,960 see that there's a bunch of code 156 00:06:04,560 --> 00:06:09,660 and some of that code loads some State 157 00:06:06,960 --> 00:06:11,460 into multiple variables and then we take 158 00:06:09,660 --> 00:06:15,000 those variables and we pass them into 159 00:06:11,460 --> 00:06:16,740 our function with many many arguments 160 00:06:15,000 --> 00:06:19,259 and then we pass those verbs again 161 00:06:16,740 --> 00:06:21,120 individually into other functions 162 00:06:19,259 --> 00:06:23,340 and while this was better than just 163 00:06:21,120 --> 00:06:24,720 having everything as Global variables it 164 00:06:23,340 --> 00:06:26,759 was so messy 165 00:06:24,720 --> 00:06:28,620 instead a better idea was to 166 00:06:26,759 --> 00:06:31,319 compartmentalize everything by putting 167 00:06:28,620 --> 00:06:33,360 these functions as part of a class 168 00:06:31,319 --> 00:06:34,680 for example by introducing a data 169 00:06:33,360 --> 00:06:36,600 holding class 170 00:06:34,680 --> 00:06:39,900 that lets me section off creating 171 00:06:36,600 --> 00:06:42,419 storing and loading the data elsewhere 172 00:06:39,900 --> 00:06:44,580 so where I was previously passing around 173 00:06:42,419 --> 00:06:46,979 all these arguments 174 00:06:44,580 --> 00:06:48,900 now when I call my function I only need 175 00:06:46,979 --> 00:06:52,080 to pass around the starter object making 176 00:06:48,900 --> 00:06:54,860 my code much simpler what do you think 177 00:06:52,080 --> 00:06:54,860 is this better 178 00:06:57,780 --> 00:07:02,400 is it the best 179 00:06:59,639 --> 00:07:03,720 no why 180 00:07:02,400 --> 00:07:05,759 well let's take a look at this distance 181 00:07:03,720 --> 00:07:07,500 checking function 182 00:07:05,759 --> 00:07:10,080 you'll see that we iterate over the 183 00:07:07,500 --> 00:07:12,660 distance list and get the port name and 184 00:07:10,080 --> 00:07:14,460 some distances and then we iterate over 185 00:07:12,660 --> 00:07:16,680 those distances 186 00:07:14,460 --> 00:07:17,819 to get the cine name and the expected 187 00:07:16,680 --> 00:07:19,919 distance 188 00:07:17,819 --> 00:07:21,180 and then we calculate the actual 189 00:07:19,919 --> 00:07:22,699 distance 190 00:07:21,180 --> 00:07:25,740 and then 191 00:07:22,699 --> 00:07:28,740 we do the check to see if it expected 192 00:07:25,740 --> 00:07:31,139 value but this isn't very intuitive 193 00:07:28,740 --> 00:07:33,300 what might make more intuitive sense 194 00:07:31,139 --> 00:07:36,180 is to go through every pair of nodes 195 00:07:33,300 --> 00:07:38,280 that we want to check the distance of 196 00:07:36,180 --> 00:07:40,979 and then have a method from an object 197 00:07:38,280 --> 00:07:43,020 that calculates the actual distance 198 00:07:40,979 --> 00:07:45,000 and another that retrieves the expected 199 00:07:43,020 --> 00:07:47,460 distance 200 00:07:45,000 --> 00:07:48,960 and this is only great for readability 201 00:07:47,460 --> 00:07:51,479 but it's also great for abstraction 202 00:07:48,960 --> 00:07:53,280 because now all these functions make it 203 00:07:51,479 --> 00:07:54,599 very easy to change the underlying 204 00:07:53,280 --> 00:07:57,180 functionality 205 00:07:54,599 --> 00:07:58,800 for example if you wanted to change and 206 00:07:57,180 --> 00:08:01,860 make optimizations to the distance 207 00:07:58,800 --> 00:08:05,580 calculation to use a faster algorithm we 208 00:08:01,860 --> 00:08:06,900 can just change that within the function 209 00:08:05,580 --> 00:08:09,120 but 210 00:08:06,900 --> 00:08:10,620 instead of passing around because 211 00:08:09,120 --> 00:08:12,900 instead of passing around an object's 212 00:08:10,620 --> 00:08:15,360 data what we really want is an interface 213 00:08:12,900 --> 00:08:17,759 to access particular kinds of data 214 00:08:15,360 --> 00:08:20,340 showing the usefulness of Designing 215 00:08:17,759 --> 00:08:22,379 around requirements 216 00:08:20,340 --> 00:08:24,120 but what I had really done was apply 217 00:08:22,379 --> 00:08:27,060 programming principles 218 00:08:24,120 --> 00:08:28,740 known as interface segregation and 219 00:08:27,060 --> 00:08:31,139 dependency inversion 220 00:08:28,740 --> 00:08:32,700 which together both dictate that 221 00:08:31,139 --> 00:08:35,640 functionality should depend on 222 00:08:32,700 --> 00:08:37,740 abstractions not the data generated by 223 00:08:35,640 --> 00:08:40,080 some unknown entity 224 00:08:37,740 --> 00:08:41,640 and if you're curious for more these 225 00:08:40,080 --> 00:08:43,020 both come from a set of five called 226 00:08:41,640 --> 00:08:44,820 solid 227 00:08:43,020 --> 00:08:46,620 but if you're not aware of these 228 00:08:44,820 --> 00:08:48,779 principles or you find them easy to 229 00:08:46,620 --> 00:08:51,180 forget then I think a better methodology 230 00:08:48,779 --> 00:08:52,140 that I found useful is always telling 231 00:08:51,180 --> 00:08:54,779 myself 232 00:08:52,140 --> 00:08:58,980 there's got to be a better way 233 00:08:54,779 --> 00:09:01,320 it might take some thinking research or 234 00:08:58,980 --> 00:09:05,220 time to find what's available to make 235 00:09:01,320 --> 00:09:06,600 code simpler better and shorter but I 236 00:09:05,220 --> 00:09:08,459 would have never got in there if I 237 00:09:06,600 --> 00:09:10,500 always think if I wasn't always thinking 238 00:09:08,459 --> 00:09:12,480 about how to do better 239 00:09:10,500 --> 00:09:15,480 and now that we've got a way to find 240 00:09:12,480 --> 00:09:17,279 issues in our code we we need a way to 241 00:09:15,480 --> 00:09:19,140 easily address them 242 00:09:17,279 --> 00:09:20,940 and I found the easiest way to do that 243 00:09:19,140 --> 00:09:23,459 is to use an integrated development 244 00:09:20,940 --> 00:09:26,100 environment like pycharm 245 00:09:23,459 --> 00:09:28,380 ideas like pycharm are quite powerful 246 00:09:26,100 --> 00:09:30,660 letting you out of the box easily do 247 00:09:28,380 --> 00:09:32,880 refactoring without any setup 248 00:09:30,660 --> 00:09:35,040 I mean look it has a refactoring menu 249 00:09:32,880 --> 00:09:38,100 Isn't that great and some of the things 250 00:09:35,040 --> 00:09:40,680 that I found quite helpful were the 251 00:09:38,100 --> 00:09:42,360 ability to rename variables everywhere 252 00:09:40,680 --> 00:09:45,000 within my project 253 00:09:42,360 --> 00:09:47,660 or fields and Method throughout the 254 00:09:45,000 --> 00:09:47,660 entire project 255 00:09:48,540 --> 00:09:54,620 it can also extract repeated blocks of 256 00:09:51,540 --> 00:09:54,620 code into a function 257 00:09:56,700 --> 00:10:01,860 uh or change the signature of a 258 00:09:59,580 --> 00:10:04,620 function's definition and updating for 259 00:10:01,860 --> 00:10:07,440 everywhere that it gets called 260 00:10:04,620 --> 00:10:11,060 it can also list usages and letting you 261 00:10:07,440 --> 00:10:11,060 quickly navigate between them 262 00:10:12,600 --> 00:10:16,740 or it also lets you move files between 263 00:10:14,700 --> 00:10:18,899 folders and updates their usages 264 00:10:16,740 --> 00:10:21,660 accordingly so now you don't have to 265 00:10:18,899 --> 00:10:24,720 change all your Imports 266 00:10:21,660 --> 00:10:27,000 and it also shows you documentation on 267 00:10:24,720 --> 00:10:28,920 hovering or you can even give you more 268 00:10:27,000 --> 00:10:30,360 extensive things 269 00:10:28,920 --> 00:10:31,399 and look I know what you might be 270 00:10:30,360 --> 00:10:34,200 thinking 271 00:10:31,399 --> 00:10:37,140 amazing lightweight editors like vim and 272 00:10:34,200 --> 00:10:39,600 vs code do that too and yes as someone 273 00:10:37,140 --> 00:10:41,940 has used both I'm sure it could 274 00:10:39,600 --> 00:10:44,760 but after I put after I had put on my 275 00:10:41,940 --> 00:10:46,500 pragmatic hat on I thought to myself is 276 00:10:44,760 --> 00:10:48,540 it really worth all the effort it would 277 00:10:46,500 --> 00:10:51,180 take to set up when all of this comes 278 00:10:48,540 --> 00:10:53,220 out of the box for free 279 00:10:51,180 --> 00:10:55,019 now something I forgot to mention that 280 00:10:53,220 --> 00:10:57,300 an IDE can also do is help you with 281 00:10:55,019 --> 00:10:59,279 types 282 00:10:57,300 --> 00:11:01,200 unlike other languages when we're 283 00:10:59,279 --> 00:11:03,660 writing small Python scripts it might 284 00:11:01,200 --> 00:11:05,700 not be worthwhile to have types but as 285 00:11:03,660 --> 00:11:08,940 our project grows 286 00:11:05,700 --> 00:11:11,459 uh type kinting can become super helpful 287 00:11:08,940 --> 00:11:14,160 for quite a few reasons one of these is 288 00:11:11,459 --> 00:11:16,140 spotting inevitable human errors 289 00:11:14,160 --> 00:11:18,899 like here we write our code to 290 00:11:16,140 --> 00:11:21,779 explicitly output a list 291 00:11:18,899 --> 00:11:23,339 but Network sex.paths returns a 292 00:11:21,779 --> 00:11:25,560 generator 293 00:11:23,339 --> 00:11:27,000 so for example if we save it as a 294 00:11:25,560 --> 00:11:29,399 variable here 295 00:11:27,000 --> 00:11:31,980 and then iterate over at once 296 00:11:29,399 --> 00:11:34,079 we'll get the expected output 297 00:11:31,980 --> 00:11:36,660 but because it's a generator when we 298 00:11:34,079 --> 00:11:38,100 iterate over it again our output will 299 00:11:36,660 --> 00:11:39,779 still be the same 300 00:11:38,100 --> 00:11:42,300 even though we might expect something 301 00:11:39,779 --> 00:11:44,100 different from a list 302 00:11:42,300 --> 00:11:46,320 but with the right tools errors like 303 00:11:44,100 --> 00:11:48,360 this can be highlighted for us 304 00:11:46,320 --> 00:11:49,800 another case is when we're unpacking an 305 00:11:48,360 --> 00:11:51,720 ester data type 306 00:11:49,800 --> 00:11:53,579 here there's nothing 307 00:11:51,720 --> 00:11:56,880 but if we do if you use some type 308 00:11:53,579 --> 00:11:58,980 annotations now we can auto complete 309 00:11:56,880 --> 00:12:02,640 with strings 310 00:11:58,980 --> 00:12:05,279 okay so now that we know what types are 311 00:12:02,640 --> 00:12:07,920 important let's go use them 312 00:12:05,279 --> 00:12:09,480 whatever you might say you have so many 313 00:12:07,920 --> 00:12:11,579 functions 314 00:12:09,480 --> 00:12:13,980 that's going to be so much work for your 315 00:12:11,579 --> 00:12:16,860 large project and you're right 316 00:12:13,980 --> 00:12:19,200 but we have technology and we can 317 00:12:16,860 --> 00:12:20,399 automate finding in adding in types for 318 00:12:19,200 --> 00:12:23,100 us 319 00:12:20,399 --> 00:12:25,560 with a tool called monkey type 320 00:12:23,100 --> 00:12:27,720 where for the following function 321 00:12:25,560 --> 00:12:30,060 can produce stops like this 322 00:12:27,720 --> 00:12:32,459 and even update your existing code so 323 00:12:30,060 --> 00:12:34,680 you don't have to edit it yourself 324 00:12:32,459 --> 00:12:36,779 of course we don't need an IDE to 325 00:12:34,680 --> 00:12:39,600 benefit from type painting but once 326 00:12:36,779 --> 00:12:41,940 typing is all set up it lets us run type 327 00:12:39,600 --> 00:12:46,620 checking tools like my pi to ensure the 328 00:12:41,940 --> 00:12:48,420 continuous checking for errors and types 329 00:12:46,620 --> 00:12:50,639 and I forgot to mention again 330 00:12:48,420 --> 00:12:52,139 typing thing is also really helpful for 331 00:12:50,639 --> 00:12:54,240 documentation 332 00:12:52,139 --> 00:12:55,380 take this function with no typing for 333 00:12:54,240 --> 00:12:57,720 example 334 00:12:55,380 --> 00:12:59,339 we can make some guesses at what most of 335 00:12:57,720 --> 00:13:01,019 these should be 336 00:12:59,339 --> 00:13:03,180 for example we could guess that names 337 00:13:01,019 --> 00:13:05,279 are probably strings 338 00:13:03,180 --> 00:13:08,459 and since we're using them to Index this 339 00:13:05,279 --> 00:13:09,600 paths argument parse is probably a 340 00:13:08,459 --> 00:13:11,880 dictionary 341 00:13:09,600 --> 00:13:14,399 that stores a list since we're iterating 342 00:13:11,880 --> 00:13:16,620 over the output 343 00:13:14,399 --> 00:13:18,480 and the function says it's returning a 344 00:13:16,620 --> 00:13:20,279 set and we have this dictionary 345 00:13:18,480 --> 00:13:21,720 comprehension so we can make a guess at 346 00:13:20,279 --> 00:13:23,940 that as well 347 00:13:21,720 --> 00:13:24,899 but with our context we're still missing 348 00:13:23,940 --> 00:13:26,339 a lot of 349 00:13:24,899 --> 00:13:29,820 um we're still missing a lot of things 350 00:13:26,339 --> 00:13:32,519 we have no clue what positions from Edge 351 00:13:29,820 --> 00:13:34,740 returns or what directions set from Edge 352 00:13:32,519 --> 00:13:37,200 returns and therefore we have to make 353 00:13:34,740 --> 00:13:38,639 guesses at why a connection path is a 354 00:13:37,200 --> 00:13:41,100 dictionary 355 00:13:38,639 --> 00:13:43,019 in fact there's no reason why pods 356 00:13:41,100 --> 00:13:45,540 couldn't be a list 357 00:13:43,019 --> 00:13:47,339 if for example the cities and ports were 358 00:13:45,540 --> 00:13:49,200 ins 359 00:13:47,339 --> 00:13:51,300 but if I properly fill in these types 360 00:13:49,200 --> 00:13:53,459 then there's a much better idea that 361 00:13:51,300 --> 00:13:57,839 connection path is actually a dictionary 362 00:13:53,459 --> 00:14:02,519 mapping between positions and directions 363 00:13:57,839 --> 00:14:04,079 and paths uh wait let me format that uh 364 00:14:02,519 --> 00:14:06,720 cool 365 00:14:04,079 --> 00:14:08,459 is actually a 2d map of names to 366 00:14:06,720 --> 00:14:10,920 positions 367 00:14:08,459 --> 00:14:12,060 and if I do some formatting to Alias the 368 00:14:10,920 --> 00:14:16,820 types 369 00:14:12,060 --> 00:14:16,820 then now it's a lot more clearer that 370 00:14:16,980 --> 00:14:22,980 um it's a lot more clearer that this 371 00:14:19,320 --> 00:14:26,220 Tuple intent is a position and 372 00:14:22,980 --> 00:14:28,500 if I you know become a bit excessive I 373 00:14:26,220 --> 00:14:31,019 could set aliases for Strings as well 374 00:14:28,500 --> 00:14:33,420 make it much more clear that you know 375 00:14:31,019 --> 00:14:36,540 we're returning a set of directions or 376 00:14:33,420 --> 00:14:39,000 we're taking in locations 377 00:14:36,540 --> 00:14:41,040 but what it does mean is that if they 378 00:14:39,000 --> 00:14:43,019 need to become classes then we can 379 00:14:41,040 --> 00:14:45,540 easily support that 380 00:14:43,019 --> 00:14:47,699 for example if we change position to be 381 00:14:45,540 --> 00:14:49,560 a class 382 00:14:47,699 --> 00:14:52,500 and with that maybe it's worth asking 383 00:14:49,560 --> 00:14:54,480 how documented is your code 384 00:14:52,500 --> 00:14:56,579 I don't just mean the number of comments 385 00:14:54,480 --> 00:14:59,760 and dog strings you've written 386 00:14:56,579 --> 00:15:01,800 or self-documenting type hints what I 387 00:14:59,760 --> 00:15:04,560 mean is does it speak for itself through 388 00:15:01,800 --> 00:15:06,540 its naming and structure like how easy 389 00:15:04,560 --> 00:15:08,100 is it for someone other than you to pick 390 00:15:06,540 --> 00:15:09,240 up and understand your code with no 391 00:15:08,100 --> 00:15:11,579 context 392 00:15:09,240 --> 00:15:13,500 if we take a look at what my repo would 393 00:15:11,579 --> 00:15:15,779 have looked like at the beginning 394 00:15:13,500 --> 00:15:17,040 here's the GitHub page with no 395 00:15:15,779 --> 00:15:18,660 description 396 00:15:17,040 --> 00:15:21,720 and 397 00:15:18,660 --> 00:15:24,959 nothing at the bottom no documentation 398 00:15:21,720 --> 00:15:26,760 or a readme four ways to start so we 399 00:15:24,959 --> 00:15:29,040 probably have to read some code 400 00:15:26,760 --> 00:15:31,620 but it's not clear which of all of these 401 00:15:29,040 --> 00:15:34,440 files are that code 402 00:15:31,620 --> 00:15:36,300 and even once we do find the file it's 403 00:15:34,440 --> 00:15:38,820 thousands of lines long 404 00:15:36,300 --> 00:15:40,620 and there is no main function to signify 405 00:15:38,820 --> 00:15:43,320 where to start 406 00:15:40,620 --> 00:15:45,180 if this was an actual Repro I probably 407 00:15:43,320 --> 00:15:47,519 would have given up my hopes of using it 408 00:15:45,180 --> 00:15:48,600 or contributing to it by now which goes 409 00:15:47,519 --> 00:15:50,579 to show 410 00:15:48,600 --> 00:15:52,860 the easier your code is to pick up and 411 00:15:50,579 --> 00:15:54,779 understand with no context the easier it 412 00:15:52,860 --> 00:15:56,519 will be for others to answer their 413 00:15:54,779 --> 00:15:58,800 questions or contribute 414 00:15:56,519 --> 00:16:00,120 now in comparison we could look at what 415 00:15:58,800 --> 00:16:02,339 we ended up with 416 00:16:00,120 --> 00:16:03,959 here's the main wrapper with only a few 417 00:16:02,339 --> 00:16:05,880 files 418 00:16:03,959 --> 00:16:06,779 and if we scroll down we'll find the 419 00:16:05,880 --> 00:16:09,300 readme 420 00:16:06,779 --> 00:16:12,060 which says that the entry point is the 421 00:16:09,300 --> 00:16:14,459 main file in the directory so if we go 422 00:16:12,060 --> 00:16:15,720 to that directory we can easily find the 423 00:16:14,459 --> 00:16:17,220 main file 424 00:16:15,720 --> 00:16:18,720 and then if we go to the bottom of that 425 00:16:17,220 --> 00:16:20,820 file 426 00:16:18,720 --> 00:16:22,500 we'll find the main method and then 427 00:16:20,820 --> 00:16:25,260 we'll see that the function being run 428 00:16:22,500 --> 00:16:27,180 comes from this helper 429 00:16:25,260 --> 00:16:30,120 so then if you go to the helper that we 430 00:16:27,180 --> 00:16:32,279 easily found in a different file 431 00:16:30,120 --> 00:16:34,560 we can easily follow what comes next 432 00:16:32,279 --> 00:16:36,720 after update map and then continue 433 00:16:34,560 --> 00:16:38,699 throughout the whole code 434 00:16:36,720 --> 00:16:40,980 in fact if we look at the entire 435 00:16:38,699 --> 00:16:44,180 structure as a whole you can see how 436 00:16:40,980 --> 00:16:44,180 these classes and packages 437 00:16:44,220 --> 00:16:50,240 make it much easier to reason about the 438 00:16:47,100 --> 00:16:50,240 different components of the project 439 00:16:50,880 --> 00:16:55,019 not only that but it Embraces another 440 00:16:52,980 --> 00:16:57,000 important programming principle 441 00:16:55,019 --> 00:16:58,920 this time the single responsibility 442 00:16:57,000 --> 00:17:02,100 principle which says that everything 443 00:16:58,920 --> 00:17:04,079 should only have one responsibility 444 00:17:02,100 --> 00:17:07,679 you can see the impact if we compare the 445 00:17:04,079 --> 00:17:10,380 main function from when I first started 446 00:17:07,679 --> 00:17:13,040 you can't see it but it's actually a 447 00:17:10,380 --> 00:17:13,040 quite long 448 00:17:14,699 --> 00:17:16,819 um 449 00:17:17,339 --> 00:17:21,360 actually let's go on a tangent while I'm 450 00:17:19,380 --> 00:17:28,079 here you might have seen the extensive 451 00:17:21,360 --> 00:17:28,079 use of uh named arguments for example in 452 00:17:28,319 --> 00:17:31,100 world map 453 00:17:31,559 --> 00:17:36,360 which might seem a bit redundant 454 00:17:34,980 --> 00:17:37,860 but 455 00:17:36,360 --> 00:17:39,840 that's because I have an utmost 456 00:17:37,860 --> 00:17:42,120 adoration for Python's beautiful 457 00:17:39,840 --> 00:17:43,860 function argument system let me explain 458 00:17:42,120 --> 00:17:46,140 why 459 00:17:43,860 --> 00:17:48,240 if we're using another language and we 460 00:17:46,140 --> 00:17:50,640 want to set up rotation to default to 461 00:17:48,240 --> 00:17:52,080 zero then we often need a function 462 00:17:50,640 --> 00:17:54,360 override 463 00:17:52,080 --> 00:17:56,340 but since python has default arguments 464 00:17:54,360 --> 00:17:58,320 there's no need for these chained 465 00:17:56,340 --> 00:18:02,039 overrides 466 00:17:58,320 --> 00:18:04,380 and often though they'll use Builders to 467 00:18:02,039 --> 00:18:07,080 resolve this issue 468 00:18:04,380 --> 00:18:09,360 that let us optionally add this data 469 00:18:07,080 --> 00:18:11,640 but yet another issue lies due to the 470 00:18:09,360 --> 00:18:13,740 nature of the required ordered arguments 471 00:18:11,640 --> 00:18:16,740 and that is that there's no knowing 472 00:18:13,740 --> 00:18:18,600 whether arguments are set up correctly 473 00:18:16,740 --> 00:18:20,400 in this case you might have not noticed 474 00:18:18,600 --> 00:18:24,080 but it should actually be width and 475 00:18:20,400 --> 00:18:24,080 height not height and width 476 00:18:24,299 --> 00:18:28,080 python resolves this with named 477 00:18:25,980 --> 00:18:30,780 arguments and thus also does away with 478 00:18:28,080 --> 00:18:32,640 builders meaning that not only are your 479 00:18:30,780 --> 00:18:35,940 functions self-documenting by having 480 00:18:32,640 --> 00:18:38,280 constant arguments labeled for you 481 00:18:35,940 --> 00:18:40,980 but now your ordering is redundant you 482 00:18:38,280 --> 00:18:43,740 can set it up however you like 483 00:18:40,980 --> 00:18:46,080 or more importantly your code is now 484 00:18:43,740 --> 00:18:48,480 always future proofed against errors 485 00:18:46,080 --> 00:18:50,880 under cases where arguments are inserted 486 00:18:48,480 --> 00:18:53,340 or ordering is changed 487 00:18:50,880 --> 00:18:55,320 and if this opened your eyes I'll be at 488 00:18:53,340 --> 00:18:57,240 the Sprints if you want to contribute to 489 00:18:55,320 --> 00:18:59,160 automatically finding and applying these 490 00:18:57,240 --> 00:19:01,559 guardrails and enhancements 491 00:18:59,160 --> 00:19:03,780 anyways where were we 492 00:19:01,559 --> 00:19:04,740 um yeah this main function was just too 493 00:19:03,780 --> 00:19:07,500 long 494 00:19:04,740 --> 00:19:09,360 and if you looked at the files you can 495 00:19:07,500 --> 00:19:11,220 see how 496 00:19:09,360 --> 00:19:12,480 what like what are these what is 497 00:19:11,220 --> 00:19:13,679 graphing and graph what is the 498 00:19:12,480 --> 00:19:15,720 difference 499 00:19:13,679 --> 00:19:19,679 if we take a look graph is actually 500 00:19:15,720 --> 00:19:20,539 storing two data classes one being quite 501 00:19:19,679 --> 00:19:25,320 long 502 00:19:20,539 --> 00:19:27,960 again you can't see it here 503 00:19:25,320 --> 00:19:31,080 but it has quite a bit of logic 504 00:19:27,960 --> 00:19:33,900 when instead we could split out them to 505 00:19:31,080 --> 00:19:36,419 be uh their own single files 506 00:19:33,900 --> 00:19:38,880 this might be of concern given the extra 507 00:19:36,419 --> 00:19:40,679 Imports and files to jump around but 508 00:19:38,880 --> 00:19:42,900 that's a trade-off to consider depending 509 00:19:40,679 --> 00:19:45,059 on how long is your class 510 00:19:42,900 --> 00:19:47,580 okay now that we've started to update 511 00:19:45,059 --> 00:19:50,039 our code what else can we do 512 00:19:47,580 --> 00:19:53,100 another good principle we can follow is 513 00:19:50,039 --> 00:19:56,100 dry or don't repeat yourself 514 00:19:53,100 --> 00:19:57,840 it's important for so many reasons here 515 00:19:56,100 --> 00:19:59,580 we have some code that repeatedly 516 00:19:57,840 --> 00:20:01,320 calculates distances 517 00:19:59,580 --> 00:20:04,080 we could refactor it by first 518 00:20:01,320 --> 00:20:06,419 introducing a function for abstraction 519 00:20:04,080 --> 00:20:09,140 and then using that function to provide 520 00:20:06,419 --> 00:20:09,140 consistency 521 00:20:09,539 --> 00:20:13,740 and then before finally introducing a 522 00:20:12,720 --> 00:20:16,440 loop 523 00:20:13,740 --> 00:20:18,539 now our code is cleaner and safer 524 00:20:16,440 --> 00:20:20,400 providing safety through reassurance 525 00:20:18,539 --> 00:20:21,660 that everything is running in the same 526 00:20:20,400 --> 00:20:23,520 way 527 00:20:21,660 --> 00:20:25,380 for example did you notice that there 528 00:20:23,520 --> 00:20:28,380 was a bug in the first example 529 00:20:25,380 --> 00:20:31,940 at the end it should actually be p3.y 530 00:20:28,380 --> 00:20:31,940 minus p2.y 531 00:20:32,400 --> 00:20:37,140 so dry allows us to be more efficient 532 00:20:34,679 --> 00:20:39,780 because now we don't need to copy or 533 00:20:37,140 --> 00:20:42,000 rewrite code to calculate distance 534 00:20:39,780 --> 00:20:44,820 or when we want to make changes like 535 00:20:42,000 --> 00:20:46,980 fixing that bug or in this case changing 536 00:20:44,820 --> 00:20:48,900 the method of square root we only need 537 00:20:46,980 --> 00:20:51,120 to do it in one place and can ensure 538 00:20:48,900 --> 00:20:53,760 that a bug fix or functionality is used 539 00:20:51,120 --> 00:20:57,179 everywhere very quickly 540 00:20:53,760 --> 00:20:59,280 but where did I apply in my code 541 00:20:57,179 --> 00:21:02,820 one example is this validation code here 542 00:20:59,280 --> 00:21:04,679 that was being used in two places 543 00:21:02,820 --> 00:21:07,140 our first thought might be to create a 544 00:21:04,679 --> 00:21:09,720 utils class but this is often not a good 545 00:21:07,140 --> 00:21:12,360 idea as it creates a new dependency that 546 00:21:09,720 --> 00:21:14,100 incentivizes us to add more small 547 00:21:12,360 --> 00:21:15,419 functionality that there isn't a good 548 00:21:14,100 --> 00:21:17,400 context for 549 00:21:15,419 --> 00:21:19,020 instead this could be moved to be inside 550 00:21:17,400 --> 00:21:21,780 validations 551 00:21:19,020 --> 00:21:24,120 and rename to validate with 552 00:21:21,780 --> 00:21:26,880 or maybe what we should really do is ask 553 00:21:24,120 --> 00:21:28,740 ourselves do we really need this 554 00:21:26,880 --> 00:21:30,900 maybe it would be better to instead 555 00:21:28,740 --> 00:21:33,780 create a grid class that ensures all 556 00:21:30,900 --> 00:21:35,760 rows of the same width or maybe we 557 00:21:33,780 --> 00:21:37,860 should ask ourselves if there's a better 558 00:21:35,760 --> 00:21:40,440 way and remove the need for this 559 00:21:37,860 --> 00:21:42,840 entirely to instill to instead deal with 560 00:21:40,440 --> 00:21:44,640 the issue when it appears 561 00:21:42,840 --> 00:21:47,100 another place we could remove repeated 562 00:21:44,640 --> 00:21:49,559 code is during the annotations 563 00:21:47,100 --> 00:21:53,100 in my map annotations are what colors 564 00:21:49,559 --> 00:21:54,900 the path between a port and a city 565 00:21:53,100 --> 00:21:57,240 and there are grouped annotations for 566 00:21:54,900 --> 00:21:59,820 both ports and cities however even 567 00:21:57,240 --> 00:22:02,220 though these are very similar and are 568 00:21:59,820 --> 00:22:04,620 done by the same mechanism we need to 569 00:22:02,220 --> 00:22:06,960 implement this slight difference since 570 00:22:04,620 --> 00:22:09,179 ports are annotated through nesting 571 00:22:06,960 --> 00:22:11,280 but conceptually this is just like 572 00:22:09,179 --> 00:22:14,580 recursion with a base case and it made 573 00:22:11,280 --> 00:22:16,500 me think there must be a better way 574 00:22:14,580 --> 00:22:18,419 and so I ingeniously thought of this 575 00:22:16,500 --> 00:22:19,860 which creates a nested list of 576 00:22:18,419 --> 00:22:21,419 specialized functions to be called with 577 00:22:19,860 --> 00:22:23,039 another generic function that could be 578 00:22:21,419 --> 00:22:24,780 used for both cities and ports and thus 579 00:22:23,039 --> 00:22:26,520 they duplicate our code 580 00:22:24,780 --> 00:22:29,340 did you get that 581 00:22:26,520 --> 00:22:31,200 no great because I quickly realized that 582 00:22:29,340 --> 00:22:32,880 I didn't either 583 00:22:31,200 --> 00:22:34,320 and even though I learned that a while I 584 00:22:32,880 --> 00:22:36,480 could give myself a pat on the back for 585 00:22:34,320 --> 00:22:38,280 This brilliant ingenuity 586 00:22:36,480 --> 00:22:40,080 what I really learned is that I should 587 00:22:38,280 --> 00:22:42,659 give myself a kick in the bum for this 588 00:22:40,080 --> 00:22:44,700 added complexity because sometimes using 589 00:22:42,659 --> 00:22:46,140 neat coding tricks to simplify code is 590 00:22:44,700 --> 00:22:48,659 not the best idea 591 00:22:46,140 --> 00:22:50,520 if it was all our code would be golfed 592 00:22:48,659 --> 00:22:52,500 to be as short as possible and that's 593 00:22:50,520 --> 00:22:55,380 just not readable 594 00:22:52,500 --> 00:22:57,720 so it's often worth considering will the 595 00:22:55,380 --> 00:22:59,400 method of our refactoring really help or 596 00:22:57,720 --> 00:23:01,980 more importantly in bringing up another 597 00:22:59,400 --> 00:23:03,059 principle are we keeping it simple 598 00:23:01,980 --> 00:23:05,280 stupid 599 00:23:03,059 --> 00:23:07,320 our aim should always be to simplify a 600 00:23:05,280 --> 00:23:10,380 code and remove what might not be needed 601 00:23:07,320 --> 00:23:12,360 not introduce added complexity 602 00:23:10,380 --> 00:23:13,440 eventually I settled in a class like 603 00:23:12,360 --> 00:23:16,559 this 604 00:23:13,440 --> 00:23:18,780 that could be inherited and override to 605 00:23:16,559 --> 00:23:20,460 provide the extensibility that I was 606 00:23:18,780 --> 00:23:22,679 looking for 607 00:23:20,460 --> 00:23:24,900 but was that extensibility that I needed 608 00:23:22,679 --> 00:23:28,799 maybe it's worth Consulting another 609 00:23:24,900 --> 00:23:29,640 principle yagni or you ain't gonna need 610 00:23:28,799 --> 00:23:32,039 it 611 00:23:29,640 --> 00:23:34,380 because we should we really be 612 00:23:32,039 --> 00:23:36,240 refactoring for things that don't exist 613 00:23:34,380 --> 00:23:39,299 thus I'll still always have a feeling 614 00:23:36,240 --> 00:23:42,120 that there's got to be a better way 615 00:23:39,299 --> 00:23:44,460 okay but how can we be confident that we 616 00:23:42,120 --> 00:23:46,320 can make all these changes while keeping 617 00:23:44,460 --> 00:23:49,080 functionality the same 618 00:23:46,320 --> 00:23:51,299 well isn't that what tests are for in 619 00:23:49,080 --> 00:23:52,679 fact having good tests is likely one of 620 00:23:51,299 --> 00:23:55,380 the most important things to have while 621 00:23:52,679 --> 00:23:57,179 refactoring because if we have tests to 622 00:23:55,380 --> 00:23:59,520 lean on then we can make all the changes 623 00:23:57,179 --> 00:24:02,039 that we want run our tests and if they 624 00:23:59,520 --> 00:24:04,140 pass then we're good to go 625 00:24:02,039 --> 00:24:05,460 tests aren't always the easiest thing to 626 00:24:04,140 --> 00:24:06,960 set up though especially under 627 00:24:05,460 --> 00:24:09,539 complexity 628 00:24:06,960 --> 00:24:11,640 but even having very basic tests where a 629 00:24:09,539 --> 00:24:14,280 program's correctness might even be 630 00:24:11,640 --> 00:24:16,500 manually verified is better than nothing 631 00:24:14,280 --> 00:24:18,539 since once that's done it can be a 632 00:24:16,500 --> 00:24:19,980 starting point into automating it using 633 00:24:18,539 --> 00:24:21,960 integration tests 634 00:24:19,980 --> 00:24:24,480 since with lots of refactoring unit 635 00:24:21,960 --> 00:24:27,780 tests may require too many changes 636 00:24:24,480 --> 00:24:29,760 for example this data class 637 00:24:27,780 --> 00:24:31,799 takes in some file names 638 00:24:29,760 --> 00:24:34,440 and create some state which can be 639 00:24:31,799 --> 00:24:37,559 easily tested by an integration test 640 00:24:34,440 --> 00:24:39,600 as in our test we can just create the 641 00:24:37,559 --> 00:24:41,820 file to test against 642 00:24:39,600 --> 00:24:44,100 but it may become really hard to test 643 00:24:41,820 --> 00:24:45,659 the functions of a class like this as 644 00:24:44,100 --> 00:24:48,480 different files will be needed to create 645 00:24:45,659 --> 00:24:50,280 to be created for every test not only 646 00:24:48,480 --> 00:24:52,320 that but it's not clear what's inside 647 00:24:50,280 --> 00:24:54,059 these files 648 00:24:52,320 --> 00:24:55,980 if you haven't noticed this is because 649 00:24:54,059 --> 00:24:57,539 it violates the dependency inversion 650 00:24:55,980 --> 00:24:59,700 principle 651 00:24:57,539 --> 00:25:01,559 in a way we can fix that is to instead 652 00:24:59,700 --> 00:25:02,820 change our class to be composed of this 653 00:25:01,559 --> 00:25:04,860 data 654 00:25:02,820 --> 00:25:06,840 and then use a cloth method that will 655 00:25:04,860 --> 00:25:09,539 take in these file names 656 00:25:06,840 --> 00:25:12,120 and create the data needed 657 00:25:09,539 --> 00:25:14,580 to pass into the class 658 00:25:12,120 --> 00:25:17,520 now in our code we can continue to 659 00:25:14,580 --> 00:25:20,039 create data using the file names 660 00:25:17,520 --> 00:25:22,020 but in our tests we can specify that the 661 00:25:20,039 --> 00:25:24,480 data that we want to be used which makes 662 00:25:22,020 --> 00:25:26,580 things much clearer 663 00:25:24,480 --> 00:25:28,679 and now while tests might ensure that 664 00:25:26,580 --> 00:25:30,240 your program stays the same they don't 665 00:25:28,679 --> 00:25:31,799 really ensure that your program doesn't 666 00:25:30,240 --> 00:25:33,840 slow down 667 00:25:31,799 --> 00:25:36,659 it's often not obvious when code can be 668 00:25:33,840 --> 00:25:38,400 slow especially with python and more so 669 00:25:36,659 --> 00:25:39,900 when we're trying to ensure that we're 670 00:25:38,400 --> 00:25:42,299 not spending time in premature 671 00:25:39,900 --> 00:25:44,400 optimization 672 00:25:42,299 --> 00:25:47,100 a profiler like scaling can be helpful 673 00:25:44,400 --> 00:25:49,020 in analyzing the runtime of our code to 674 00:25:47,100 --> 00:25:51,419 determine where there's inefficiencies 675 00:25:49,020 --> 00:25:53,880 in Computing or memory 676 00:25:51,419 --> 00:25:55,860 for example this was the output I got 677 00:25:53,880 --> 00:25:57,840 when I started to notice my code started 678 00:25:55,860 --> 00:26:00,960 to be slow and I couldn't really figure 679 00:25:57,840 --> 00:26:02,580 out what change I did to cause it 680 00:26:00,960 --> 00:26:04,020 and here we can see that this is 681 00:26:02,580 --> 00:26:05,700 actually caused by the creation of 682 00:26:04,020 --> 00:26:07,679 coordinates 683 00:26:05,700 --> 00:26:09,960 because what I had done was set up my 684 00:26:07,679 --> 00:26:13,740 code in such a way to compute the values 685 00:26:09,960 --> 00:26:16,679 of a field on the classes creation 686 00:26:13,740 --> 00:26:18,840 but the edge nodes aren't always needed 687 00:26:16,679 --> 00:26:21,179 instead I could move this field to a 688 00:26:18,840 --> 00:26:22,919 function instead only being run when 689 00:26:21,179 --> 00:26:25,140 needed 690 00:26:22,919 --> 00:26:27,299 but maybe I wanted this as a property 691 00:26:25,140 --> 00:26:30,240 since it's easier to read and implies 692 00:26:27,299 --> 00:26:31,980 it's a value that shouldn't change 693 00:26:30,240 --> 00:26:33,900 well we can do that with a property 694 00:26:31,980 --> 00:26:36,600 built-in decorator which lets us return 695 00:26:33,900 --> 00:26:38,580 a function's output as a field 696 00:26:36,600 --> 00:26:40,559 but a value shouldn't always be 697 00:26:38,580 --> 00:26:42,120 recomputed if it's not going to return 698 00:26:40,559 --> 00:26:44,760 the same thing 699 00:26:42,120 --> 00:26:46,919 this is where the func tools.cash 700 00:26:44,760 --> 00:26:49,500 decorator comes in which saves the 701 00:26:46,919 --> 00:26:51,360 output of a function so that we don't 702 00:26:49,500 --> 00:26:53,159 have to recompute it 703 00:26:51,360 --> 00:26:57,059 this is great for values that we access 704 00:26:53,159 --> 00:26:59,340 many times but only want to compute once 705 00:26:57,059 --> 00:27:01,679 we could use both to solve this issue 706 00:26:59,340 --> 00:27:03,720 however it's worth noting that it can 707 00:27:01,679 --> 00:27:05,820 lead to memory leaks as the cache May 708 00:27:03,720 --> 00:27:07,559 retain instance references preventing 709 00:27:05,820 --> 00:27:09,720 garbage collection 710 00:27:07,559 --> 00:27:11,460 the solution is to use the cached 711 00:27:09,720 --> 00:27:12,840 property decorator which does both in 712 00:27:11,460 --> 00:27:15,240 one go 713 00:27:12,840 --> 00:27:17,159 and easily one of my favorite Python 714 00:27:15,240 --> 00:27:19,500 built-ins and one that resolves so many 715 00:27:17,159 --> 00:27:21,480 lintel warnings too 716 00:27:19,500 --> 00:27:23,159 all right that's our profiling and 717 00:27:21,480 --> 00:27:25,440 optimization done 718 00:27:23,159 --> 00:27:27,299 but I wonder whether my refactoring 719 00:27:25,440 --> 00:27:28,500 story would be fast or slow if I 720 00:27:27,299 --> 00:27:31,080 profiled it 721 00:27:28,500 --> 00:27:34,260 how much time do I have left 722 00:27:31,080 --> 00:27:36,360 okay well that was quite a fun story 723 00:27:34,260 --> 00:27:38,940 you might be wondering though what about 724 00:27:36,360 --> 00:27:39,779 the profit did I get the help that I 725 00:27:38,940 --> 00:27:42,480 needed 726 00:27:39,779 --> 00:27:44,279 yes I did but there's still plenty of 727 00:27:42,480 --> 00:27:45,840 more to figure out 728 00:27:44,279 --> 00:27:48,240 and while you could say that there is 729 00:27:45,840 --> 00:27:50,520 profit and saving time in the future 730 00:27:48,240 --> 00:27:53,039 I think the real profit though was 731 00:27:50,520 --> 00:27:54,840 everything that I learned along the way 732 00:27:53,039 --> 00:27:56,580 if you wanted to profit yourself I've 733 00:27:54,840 --> 00:27:57,720 put up some resources here that you can 734 00:27:56,580 --> 00:28:01,140 reference later 735 00:27:57,720 --> 00:28:03,200 I'll leave this on for a couple seconds 736 00:28:01,140 --> 00:28:03,200 um 737 00:28:04,140 --> 00:28:08,039 pool 738 00:28:06,179 --> 00:28:10,860 can also talk to me later 739 00:28:08,039 --> 00:28:12,179 um but yes I want to say thanks to my 740 00:28:10,860 --> 00:28:14,340 partner and all my friends for 741 00:28:12,179 --> 00:28:15,600 supporting me and thanks to all of you 742 00:28:14,340 --> 00:28:17,340 for listening 743 00:28:15,600 --> 00:28:19,100 I would love to hear any feedback that 744 00:28:17,340 --> 00:28:22,200 you have I'm always trying to improve 745 00:28:19,100 --> 00:28:24,120 and you can find me online at ecohillas 746 00:28:22,200 --> 00:28:25,380 or GitHub if you wanted to take a look 747 00:28:24,120 --> 00:28:27,299 at my code 748 00:28:25,380 --> 00:28:29,220 however I won't claim that my code is 749 00:28:27,299 --> 00:28:30,480 perfect because I think there's always a 750 00:28:29,220 --> 00:28:32,880 better way 751 00:28:30,480 --> 00:28:34,620 you can also find me in person right 752 00:28:32,880 --> 00:28:37,820 here as I think we still have some time 753 00:28:34,620 --> 00:28:37,820 for questions thank you 754 00:28:43,620 --> 00:28:47,419 yep I think we've got time for questions 755 00:28:51,360 --> 00:28:57,360 I'll put the QR code up as well 756 00:28:55,140 --> 00:28:59,940 um all right um I think that was that 757 00:28:57,360 --> 00:29:03,539 was a great talk cute 758 00:28:59,940 --> 00:29:05,640 but I do have a questions in in an ideal 759 00:29:03,539 --> 00:29:07,620 world where you go into a project 760 00:29:05,640 --> 00:29:10,200 there's a whole bunch of tests 761 00:29:07,620 --> 00:29:12,779 um 100 coverage for example then you can 762 00:29:10,200 --> 00:29:15,059 ensure that no changes or your 763 00:29:12,779 --> 00:29:18,539 refactoring doesn't accidentally change 764 00:29:15,059 --> 00:29:21,059 any functionality but there are cases 765 00:29:18,539 --> 00:29:22,500 where you go in and there's no test what 766 00:29:21,059 --> 00:29:25,200 would you do in that case you ensure 767 00:29:22,500 --> 00:29:28,559 that you don't accidents accidentally 768 00:29:25,200 --> 00:29:30,620 change things yeah that's really hard 769 00:29:28,559 --> 00:29:30,620 um 770 00:29:31,799 --> 00:29:37,020 so when when I started I basically had 771 00:29:34,620 --> 00:29:38,340 this tool that I would run and I didn't 772 00:29:37,020 --> 00:29:39,899 have any tests because I just wanted 773 00:29:38,340 --> 00:29:42,059 things to work 774 00:29:39,899 --> 00:29:44,640 um and what I did was I just 775 00:29:42,059 --> 00:29:45,779 would run it and then visually check it 776 00:29:44,640 --> 00:29:47,399 um we'll run it and really visually 777 00:29:45,779 --> 00:29:50,820 check it and I will do that over and 778 00:29:47,399 --> 00:29:53,220 over and uh I think you need to have 779 00:29:50,820 --> 00:29:54,960 some kind of test you need to have some 780 00:29:53,220 --> 00:29:58,080 kind of method 781 00:29:54,960 --> 00:30:00,000 um even if it's just like 782 00:29:58,080 --> 00:30:01,919 create an instance of what the output 783 00:30:00,000 --> 00:30:03,480 should be and then check that it's the 784 00:30:01,919 --> 00:30:04,980 same 785 00:30:03,480 --> 00:30:06,779 um 786 00:30:04,980 --> 00:30:08,340 and then at some point once you've 787 00:30:06,779 --> 00:30:10,039 started refactoring and changing all 788 00:30:08,340 --> 00:30:13,620 that you can then 789 00:30:10,039 --> 00:30:15,740 start to introduce better tests that you 790 00:30:13,620 --> 00:30:19,500 can make sure that all this is the same 791 00:30:15,740 --> 00:30:21,419 in terms of existing code bases I'm not 792 00:30:19,500 --> 00:30:23,539 100 sure 793 00:30:21,419 --> 00:30:23,539 um 794 00:30:24,059 --> 00:30:29,279 I guess look at the entry point and the 795 00:30:27,539 --> 00:30:31,740 exit point and see what you're trying to 796 00:30:29,279 --> 00:30:33,659 compare it's probably a topic for 797 00:30:31,740 --> 00:30:35,760 another talk on testing 798 00:30:33,659 --> 00:30:39,860 um yeah does that answer your question 799 00:30:35,760 --> 00:30:39,860 yeah thank you awesome thank you 800 00:30:45,059 --> 00:30:50,580 hi this is a question about typing and 801 00:30:47,940 --> 00:30:52,559 documentation so uh when using say 802 00:30:50,580 --> 00:30:54,720 Django 803 00:30:52,559 --> 00:30:56,880 um it's hard to do you use my pie 804 00:30:54,720 --> 00:30:58,320 because you know for my pie to work it 805 00:30:56,880 --> 00:31:00,179 has to run all the code and that's 806 00:30:58,320 --> 00:31:04,080 really hard with Django 807 00:31:00,179 --> 00:31:06,240 uh so typing is not that useful because 808 00:31:04,080 --> 00:31:08,279 you have there's all these libraries 809 00:31:06,240 --> 00:31:11,220 that enable using Wi-Fi but they're a 810 00:31:08,279 --> 00:31:15,600 pain so typing isn't that useful in 811 00:31:11,220 --> 00:31:18,419 Django is there um a format of sort of 812 00:31:15,600 --> 00:31:21,299 Doc strings that you've uh that you're 813 00:31:18,419 --> 00:31:24,299 aware of that uh are a good replacement 814 00:31:21,299 --> 00:31:26,580 for typing yes 815 00:31:24,299 --> 00:31:30,120 um so 816 00:31:26,580 --> 00:31:31,860 uh you don't actually need to use mypai 817 00:31:30,120 --> 00:31:34,260 to tell you whether things are correct 818 00:31:31,860 --> 00:31:37,140 or not and you don't actually need to 819 00:31:34,260 --> 00:31:39,059 put in the typing you can also just put 820 00:31:37,140 --> 00:31:40,140 comments that's originally how typing 821 00:31:39,059 --> 00:31:41,700 was done 822 00:31:40,140 --> 00:31:42,860 um there's a certain syntax I don't 823 00:31:41,700 --> 00:31:46,679 remember 824 00:31:42,860 --> 00:31:48,600 you can also just use doc strings as you 825 00:31:46,679 --> 00:31:49,980 mentioned to 826 00:31:48,600 --> 00:31:52,260 um 827 00:31:49,980 --> 00:31:55,140 you can use doc strings to just make 828 00:31:52,260 --> 00:31:59,039 your own system or use an existing 829 00:31:55,140 --> 00:32:00,779 system because really like the point if 830 00:31:59,039 --> 00:32:03,299 you have typing it's nice because then 831 00:32:00,779 --> 00:32:04,620 you can validate against everything 832 00:32:03,299 --> 00:32:08,100 um 833 00:32:04,620 --> 00:32:10,799 but you don't really need that 834 00:32:08,100 --> 00:32:12,299 validation you what you really need is 835 00:32:10,799 --> 00:32:13,740 some way to 836 00:32:12,299 --> 00:32:16,919 you know you might be working at 837 00:32:13,740 --> 00:32:19,559 something and then you want to check 838 00:32:16,919 --> 00:32:22,500 okay what 839 00:32:19,559 --> 00:32:24,059 um what is this function outputting 840 00:32:22,500 --> 00:32:25,440 um if you just go to that function's 841 00:32:24,059 --> 00:32:26,880 definition and then look at the doc 842 00:32:25,440 --> 00:32:29,340 string 843 00:32:26,880 --> 00:32:31,260 provided this developer has like put 844 00:32:29,340 --> 00:32:33,419 something there for you even that's a 845 00:32:31,260 --> 00:32:35,039 really good start and then over time 846 00:32:33,419 --> 00:32:37,260 when things get better you can start 847 00:32:35,039 --> 00:32:39,899 adding more typing Etc 848 00:32:37,260 --> 00:32:43,679 does that help uh yeah like so my 849 00:32:39,899 --> 00:32:45,899 problem is like uh there's no pep for uh 850 00:32:43,679 --> 00:32:49,740 doc strings where it says how to define 851 00:32:45,899 --> 00:32:51,919 arguments right okay uh 852 00:32:49,740 --> 00:32:51,919 um 853 00:32:53,880 --> 00:32:57,480 I have a feeling that the there should 854 00:32:55,980 --> 00:32:58,679 be 855 00:32:57,480 --> 00:33:01,020 um I 856 00:32:58,679 --> 00:33:03,659 I'm not sure I think I've seen a lintel 857 00:33:01,020 --> 00:33:06,240 warning where it's something like ensure 858 00:33:03,659 --> 00:33:07,860 that it tells you what it returns I have 859 00:33:06,240 --> 00:33:10,260 I think I have seen functions that tell 860 00:33:07,860 --> 00:33:12,059 you like texting these arguments returns 861 00:33:10,260 --> 00:33:14,640 this it might not be a type definition 862 00:33:12,059 --> 00:33:17,039 but it might just be like a wordy 863 00:33:14,640 --> 00:33:19,019 definition at the least 864 00:33:17,039 --> 00:33:21,360 um it's a it's a hard question yeah it's 865 00:33:19,019 --> 00:33:25,200 a hard problem and would you ever prefer 866 00:33:21,360 --> 00:33:27,059 uh sometimes when um the typing is a 867 00:33:25,200 --> 00:33:29,460 complex thing there's a dictionary of 868 00:33:27,059 --> 00:33:31,919 lists of sets of whatever these 869 00:33:29,460 --> 00:33:35,279 sometimes prefer to just omit that and 870 00:33:31,919 --> 00:33:39,539 just write a dog string describing what 871 00:33:35,279 --> 00:33:41,279 what it is and adding context to why 872 00:33:39,539 --> 00:33:43,620 yeah that's what you want in this 873 00:33:41,279 --> 00:33:45,500 function yeah I had that case pop up 874 00:33:43,620 --> 00:33:48,779 when I um 875 00:33:45,500 --> 00:33:50,279 was importing like Json and that Json 876 00:33:48,779 --> 00:33:51,600 would be converted to dictionary and it 877 00:33:50,279 --> 00:33:53,460 was like oh this massive really long 878 00:33:51,600 --> 00:33:54,659 dictionary like could be a string or it 879 00:33:53,460 --> 00:33:56,240 could be um 880 00:33:54,659 --> 00:34:00,840 well 881 00:33:56,240 --> 00:34:01,919 uh it could be a string or it could be a 882 00:34:00,840 --> 00:34:04,080 um 883 00:34:01,919 --> 00:34:04,799 an into etc etc 884 00:34:04,080 --> 00:34:06,659 um 885 00:34:04,799 --> 00:34:08,700 I think in that case I just opted to 886 00:34:06,659 --> 00:34:10,560 remove it but another thing you could do 887 00:34:08,700 --> 00:34:13,500 is to just 888 00:34:10,560 --> 00:34:15,359 um save that as an alias somewhere 889 00:34:13,500 --> 00:34:17,520 um and just say Okay this return to 890 00:34:15,359 --> 00:34:20,639 Jason now Jason is formatted like this 891 00:34:17,520 --> 00:34:23,700 and then call it a day yeah 892 00:34:20,639 --> 00:34:26,040 yeah thanks thank you 893 00:34:23,700 --> 00:34:29,000 thanks Evan for a great talk here's a 894 00:34:26,040 --> 00:34:29,000 token of our appreciation 895 00:34:30,960 --> 00:34:33,980 thank you very much