WEBVTT 00:00:00.001 --> 00:00:07.240 Clean code is one of those aspects of your programming career that's easy to put on the back burner, sometimes more by management than yourself. 00:00:07.240 --> 00:00:11.960 But it's important in the short term for writing more debuggable and readable code. 00:00:11.960 --> 00:00:18.800 And it's important in the long run for avoiding having your program take on the dreaded legacy code moniker. 00:00:18.800 --> 00:00:22.160 We're fortunate to have Bob Bilderbos back on the show. 00:00:22.160 --> 00:00:25.860 He's been thinking and writing about clean code and Python a lot lately. 00:00:26.080 --> 00:00:33.980 And we'll dive into a bunch of tips that you can use right away to make your code cleaner, more fun to work with, easier to read, and more maintainable. 00:00:33.980 --> 00:00:39.640 This is Talk Python To Me, episode 404, recorded February 12th, 2023. 00:00:53.000 --> 00:00:56.460 Welcome to Talk Python To Me, a weekly podcast on Python. 00:00:56.460 --> 00:00:58.200 This is your host, Michael Kennedy. 00:00:58.200 --> 00:01:05.680 Follow me on Mastodon, where I'm @mkennedy, and follow the podcast using @talkpython, both on fosstodon.org. 00:01:05.680 --> 00:01:08.300 Be careful with impersonating accounts on other instances. 00:01:08.300 --> 00:01:09.260 There are many. 00:01:09.260 --> 00:01:14.320 Keep up with the show and listen to over seven years of past episodes at talkpython.fm. 00:01:14.780 --> 00:01:18.360 We've started streaming most of our episodes live on YouTube. 00:01:18.360 --> 00:01:25.920 Subscribe to our YouTube channel over at talkpython.fm/youtube to get notified about upcoming shows and be part of that episode. 00:01:27.000 --> 00:01:29.920 This episode of Talk Python is brought to you by Taipy. 00:01:29.920 --> 00:01:36.520 They're here to take on the challenge of rapidly transforming a Bayer algorithm in Python into a full-fledged decision support system. 00:01:36.520 --> 00:01:41.320 Check them out at talkpython.fm/taipy, T-A-I-P-Y. 00:01:41.320 --> 00:01:44.560 And it's also brought to you by my friends over at Brilliant. 00:01:44.560 --> 00:01:51.680 Stay on top of technology and raise your value to employers, or just learn something fun in STEM at Brilliant.org. 00:01:51.880 --> 00:01:57.340 Visit talkpython.fm/brilliant to get 20% off an annual premium subscription. 00:01:57.340 --> 00:02:00.060 Bob, welcome back to Talk Python To Me. 00:02:00.060 --> 00:02:01.580 Thanks for having me back. 00:02:01.580 --> 00:02:02.760 I'm excited to be here. 00:02:02.760 --> 00:02:04.300 Yeah, it's really great to have you back. 00:02:04.300 --> 00:02:05.640 You've been on a couple of times. 00:02:05.640 --> 00:02:12.840 We started, I believe, our first discussion on the show way back when was around 100 days of code. 00:02:12.840 --> 00:02:20.260 We went on quite the 100 days of code journey, writing a couple of really, really long courses that were well-received, 00:02:20.260 --> 00:02:23.700 but it took a long, you know, like nine months for us to write, which was amazing. 00:02:23.700 --> 00:02:25.260 And we're back together. 00:02:25.260 --> 00:02:25.940 It's great to catch up. 00:02:25.940 --> 00:02:26.680 Yeah, indeed. 00:02:26.680 --> 00:02:31.240 Yeah, that goes way back to 100 days of Python and two courses that came from it. 00:02:31.240 --> 00:02:33.500 And I think we also did a Django episode. 00:02:33.500 --> 00:02:34.160 Yeah. 00:02:34.160 --> 00:02:35.240 That's right. 00:02:35.240 --> 00:02:36.720 We did do a Django episode as well. 00:02:36.720 --> 00:02:37.460 Good stuff. 00:02:37.460 --> 00:02:42.900 So this time we're back to talk about code quality, writing clean code. 00:02:42.900 --> 00:02:44.320 What are some of the tools? 00:02:44.320 --> 00:02:56.300 And also what are some of the techniques, maybe even mindset people are using to help them write clean code, better code, both for yourself to make yourself happy and as well to be a better teammate if you're working in a team, right? 00:02:56.300 --> 00:02:56.700 Yeah. 00:02:56.700 --> 00:02:58.100 This topic really excites me. 00:02:58.100 --> 00:02:59.500 It's in my everyday work. 00:02:59.500 --> 00:03:01.760 And I think there's a lot to gain from it. 00:03:01.760 --> 00:03:02.740 So, yeah. 00:03:02.740 --> 00:03:03.840 Excited to share today. 00:03:03.840 --> 00:03:04.520 I am too. 00:03:04.600 --> 00:03:07.020 It's something I really, really care a lot about. 00:03:07.020 --> 00:03:12.780 It's one of those topics that I think is long lived, which is rare in software development. 00:03:12.780 --> 00:03:18.300 It's not the latest JavaScript framework or something that's going to last for a year or two. 00:03:18.300 --> 00:03:26.680 These ideas are the kind of ideas that just no matter what you're doing, even if you don't do Python, if you do something else, it's very likely that these are solid foundations. 00:03:26.680 --> 00:03:29.980 Some of the ideas will be specifically for Python, but many of them not. 00:03:29.980 --> 00:03:30.260 Yeah. 00:03:30.260 --> 00:03:31.020 Timeless stuff. 00:03:31.020 --> 00:03:31.260 Yeah. 00:03:31.260 --> 00:03:33.880 Those are the good ones that are worth putting your time into learning. 00:03:34.400 --> 00:03:39.120 Now, before we jump into that topic, which is going to be good, maybe just tell people what you're up to. 00:03:39.120 --> 00:03:42.020 These days, so I left Oracle a while back. 00:03:42.020 --> 00:03:44.040 I think we spoke about that in 2020. 00:03:44.040 --> 00:03:47.720 So, I've been working on PyBytes full-time for almost three years. 00:03:47.720 --> 00:03:48.400 Congratulations. 00:03:48.400 --> 00:03:53.500 I know you and I spoke about this beforehand, and it was really a big step for you. 00:03:53.500 --> 00:03:54.200 It was. 00:03:54.200 --> 00:03:56.980 And something you were absolutely looking forward to. 00:03:56.980 --> 00:04:00.760 But just walking away from a good-paying job, that's scary. 00:04:00.760 --> 00:04:01.160 Stuff. 00:04:01.160 --> 00:04:02.080 So, congratulations. 00:04:02.080 --> 00:04:03.160 Yeah, thanks. 00:04:03.480 --> 00:04:07.540 This is also around the time that, as PyBytes, we pivoted to doing coaching. 00:04:07.540 --> 00:04:09.580 So, helping people one-on-one. 00:04:09.580 --> 00:04:12.240 We created our PyBites Developer Mindset Program. 00:04:12.240 --> 00:04:13.880 It's a coaching program. 00:04:13.880 --> 00:04:15.460 And that really took off. 00:04:15.460 --> 00:04:17.520 And we have worked now with 100-plus people. 00:04:17.520 --> 00:04:21.200 But I'm super excited about every day when I wake up. 00:04:21.200 --> 00:04:30.520 Because helping people overcoming the tutorial paralysis, embracing imposter syndrome, helping them shipping to projects end-to-end is just the best thing ever. 00:04:30.520 --> 00:04:30.920 Yeah. 00:04:30.920 --> 00:04:34.460 To see people grow and become more confident and get better. 00:04:34.460 --> 00:04:36.860 And, yeah, it's really excellent work, isn't it? 00:04:36.920 --> 00:04:37.940 Yeah, it's really fulfilling. 00:04:37.940 --> 00:04:38.260 Yeah. 00:04:38.260 --> 00:04:39.420 So, congratulations. 00:04:39.420 --> 00:04:41.540 It's awesome to hear that you're doing that now. 00:04:41.540 --> 00:04:48.780 And you can put all of your energy, not just your side hustle energy, into these types of things, which I can tell you feels real good. 00:04:49.040 --> 00:04:50.000 You know how it is, right? 00:04:50.000 --> 00:04:51.680 I do, I do. 00:04:51.680 --> 00:04:52.580 I've been in it for a while. 00:04:52.580 --> 00:04:53.520 Very fortunate. 00:04:53.520 --> 00:04:53.880 Okay. 00:04:53.880 --> 00:04:58.040 So, let's start this off with looking at your article. 00:04:58.040 --> 00:05:03.380 But before we do, Toon Army Captain has a really great way to sort of kick off this topic, I believe. 00:05:03.380 --> 00:05:07.460 Clean Code has less or fewer WTFs per line. 00:05:07.460 --> 00:05:08.280 How about that? 00:05:08.280 --> 00:05:08.720 Nice. 00:05:08.720 --> 00:05:12.240 So, yeah, I think that's going to be a theme here. 00:05:12.240 --> 00:05:14.120 Let's go ahead and jump into it. 00:05:14.120 --> 00:05:17.200 I reached out to you and said, hey, let's get together and talk about this. 00:05:17.460 --> 00:05:20.100 Because I knew that you were passionate about these things. 00:05:20.100 --> 00:05:26.360 But then you also put together a blog post here called Tips for Clean Code in Python. 00:05:26.360 --> 00:05:27.940 And I thought, okay, that's interesting. 00:05:27.940 --> 00:05:29.140 Let me start flipping through here. 00:05:29.140 --> 00:05:32.660 And there's just a bunch of nice ideas that, you know, resonate with me. 00:05:32.660 --> 00:05:36.000 So, what I thought we could do is maybe you could set the stage. 00:05:36.000 --> 00:05:37.380 Like, what the heck is Clean Code? 00:05:37.380 --> 00:05:41.180 Toon Army did do a pretty good job of kind of giving us the colloquial term. 00:05:41.180 --> 00:05:45.080 But, you know, maybe something a little more saphoric and formal we could go with. 00:05:45.460 --> 00:05:47.580 Set the stage for what is Clean Code? 00:05:47.580 --> 00:05:48.740 Why does it matter? 00:05:48.740 --> 00:05:52.300 And then we could dive into some of the stuff you put into your article. 00:05:52.300 --> 00:05:57.340 And then also, you and I both threw some ideas in after, like, kind of expanded as well. 00:05:57.340 --> 00:05:59.660 So, let's start with what is this Clean Code thing? 00:05:59.660 --> 00:06:00.160 Yeah. 00:06:00.160 --> 00:06:01.180 To set off the stage. 00:06:01.180 --> 00:06:07.840 So, Clean Code is really when you write code that's easier to maintain, easier to test, easier to update. 00:06:07.840 --> 00:06:11.460 Because, as we all know, a project usually starts simple. 00:06:11.460 --> 00:06:12.860 But over time, it grows. 00:06:12.860 --> 00:06:14.240 New requirements comes in. 00:06:14.240 --> 00:06:16.240 You constantly have to change things. 00:06:16.240 --> 00:06:24.680 And, yeah, the cleanness of your code will definitely determine how easy you can move a project forward, how you can make changes. 00:06:25.040 --> 00:06:33.840 And, of course, it's also a contribution to your team to make it a more pleasant experience and decrease the amount of WTFs. 00:06:34.640 --> 00:06:35.560 Yeah, you don't want it. 00:06:35.560 --> 00:06:36.540 The fewer, the better. 00:06:36.540 --> 00:06:40.780 Although, maybe you'll leave in one or two in just for a good war story at a conference five years from now. 00:06:40.780 --> 00:06:42.120 But you don't want too many of those. 00:06:42.120 --> 00:06:42.580 And I was a free. 00:06:42.580 --> 00:06:42.780 Yeah. 00:06:42.780 --> 00:06:49.040 I think it's appreciating the fact that if you do a good job, what you're building will live a long time. 00:06:49.040 --> 00:06:49.540 Right? 00:06:49.560 --> 00:06:54.220 It will possibly be still the main focus in five years from now. 00:06:54.220 --> 00:06:56.360 And you don't always know what that's going to be. 00:06:56.360 --> 00:06:56.900 Right? 00:06:56.900 --> 00:06:59.260 It could be, oh, here's a little side project. 00:06:59.260 --> 00:07:01.020 It's just going to pull in some data. 00:07:01.020 --> 00:07:03.180 And, like, you know, you show it to somebody at work. 00:07:03.180 --> 00:07:03.800 I'm like, you know what? 00:07:03.800 --> 00:07:04.560 That's great. 00:07:04.560 --> 00:07:04.960 Ship it. 00:07:04.960 --> 00:07:05.700 Like, whoa, whoa, whoa, whoa. 00:07:05.700 --> 00:07:06.160 Ship it. 00:07:06.160 --> 00:07:06.620 No, no. 00:07:06.620 --> 00:07:07.580 I just threw it together. 00:07:07.580 --> 00:07:08.660 It's good. 00:07:08.660 --> 00:07:09.160 Let's go. 00:07:09.160 --> 00:07:10.360 Like, we're in a hurry, you know? 00:07:10.360 --> 00:07:17.620 And then that just starts to build and layer on, like, a sediment that just makes it harder and less fun to work with. 00:07:17.800 --> 00:07:33.940 And so as you just think about this thing is small now, but as it grows, what are both the practices and maybe technological programming things to bring and put in place so that as it grows, you don't start to just really come to a screeching halt to make changes. 00:07:33.940 --> 00:07:38.020 Tests start to fail randomly as you just touch it in various places. 00:07:38.020 --> 00:07:38.880 Things like that, right? 00:07:38.880 --> 00:07:39.320 Yeah. 00:07:39.800 --> 00:07:48.940 It was also kind of my introduction to Python in 2012, so almost 11 years ago when I made this automation framework at work. 00:07:48.940 --> 00:07:52.040 And I was a big fan of Perl back then. 00:07:52.040 --> 00:07:57.580 I guess that goes back to my Unix shell scripting initial programming exploration. 00:07:57.580 --> 00:08:00.060 And it was not maintainable at all, right? 00:08:00.060 --> 00:08:01.680 There were no classes in Perl. 00:08:01.680 --> 00:08:02.660 And it was just a mess. 00:08:02.840 --> 00:08:05.160 Also, of course, because I did no Perl maybe very well. 00:08:05.160 --> 00:08:09.620 But then I discovered Python and I could refactor it, make it more modular. 00:08:09.620 --> 00:08:13.440 And that project was then just a joy to work with. 00:08:13.440 --> 00:08:18.280 And maybe that says a lot about Python as well, that it does inherently things well. 00:08:18.280 --> 00:08:26.080 Because if you type import this in the REPL and you get the send of Python, a lot of these statements sound so simple, but they're actually so profound. 00:08:26.080 --> 00:08:30.840 And they actually tell you a lot about writing clean code, in a sense. 00:08:30.840 --> 00:08:32.840 So anyway, but I digress. 00:08:32.840 --> 00:08:33.220 They do. 00:08:33.220 --> 00:08:43.580 They also talk a lot about the community that cares enough that, you know, you have these sorts of commands in the language itself that remind you to think about writing clean code. 00:08:43.580 --> 00:08:52.960 And going way back to the late 80s, Gito, when he came up with it, really broke with tradition to use white space for the code structure. 00:08:53.520 --> 00:09:01.400 And I think it's a little bit less so now, but back then, that was very much to encourage people to write code in a way that was very readable. 00:09:01.400 --> 00:09:07.340 Whereas, you know, I say less so than now, because you've got a lot of IDEs and stuff where you can push a button and it'll auto format it. 00:09:07.340 --> 00:09:08.540 And you've got things like black. 00:09:08.540 --> 00:09:13.220 And, you know, if you had curly braces, like it could still be quickly put into a pretty shape now. 00:09:13.220 --> 00:09:16.500 But in the early days, that was a really important concept of it. 00:09:16.500 --> 00:09:18.060 These days were spoiled, right? 00:09:18.060 --> 00:09:20.380 Having black out of formatting and all that. 00:09:20.380 --> 00:09:22.460 When we started, that was not the case. 00:09:22.720 --> 00:09:26.080 How did you react to the white space thing when you first? 00:09:26.080 --> 00:09:27.060 At first, I hated it. 00:09:27.060 --> 00:09:28.280 I just really didn't like it. 00:09:28.280 --> 00:09:29.240 I thought this is just weird. 00:09:29.240 --> 00:09:34.320 Like, okay, everything else about this language seems pretty nice, but this is weird stuff. 00:09:34.320 --> 00:09:36.900 Then I started using editors that understood it. 00:09:36.900 --> 00:09:39.440 It's like, okay, well, I just hit, you know, colon and enter. 00:09:39.440 --> 00:09:41.500 And it kind of does it for me automatically. 00:09:41.500 --> 00:09:43.560 And sure, there's three spaces, four spaces. 00:09:43.560 --> 00:09:46.100 But if I backspace, then it goes back forward. 00:09:46.400 --> 00:09:48.340 It kind of treats the structure. 00:09:48.340 --> 00:09:49.980 The tools know the structure. 00:09:49.980 --> 00:09:51.060 And it makes it really nice. 00:09:51.060 --> 00:09:55.380 And at the time, this is long ago, I was doing C#, which is an okay language. 00:09:55.380 --> 00:09:55.920 It's pretty good. 00:09:55.920 --> 00:10:02.480 But it has all the symbols and formulas and all the angle brackets and all the stuff that you would do, right? 00:10:02.480 --> 00:10:04.320 It's not quite C++, but it's pretty close. 00:10:04.800 --> 00:10:08.940 And when I came to Python, I was like, gosh, it's just weird that a lot of that stuff's not here. 00:10:08.940 --> 00:10:10.440 And it seemed kind of out of place. 00:10:10.440 --> 00:10:14.040 But then when I went back, I realized, wait, these languages are lying to me. 00:10:14.040 --> 00:10:16.840 They're saying I need all these symbols to make it hold together. 00:10:16.840 --> 00:10:17.980 And you just don't. 00:10:17.980 --> 00:10:23.420 And it's so much nicer to look at code that is not laden with these support structures. 00:10:23.420 --> 00:10:25.080 So a bit of a diversion. 00:10:25.080 --> 00:10:27.740 But yeah, I reacted weirdly to it. 00:10:27.740 --> 00:10:30.120 But after about a week, I'm like, but it's better. 00:10:30.120 --> 00:10:31.300 It really is. 00:10:31.300 --> 00:10:33.060 Even though I'm so weirded out by it, it's better. 00:10:33.060 --> 00:10:35.720 And then, you know, pretty quickly, I'm like, yeah, this is sweet. 00:10:35.720 --> 00:10:36.400 I'm going with this. 00:10:36.400 --> 00:10:37.120 Yeah, same here. 00:10:37.120 --> 00:10:38.500 Indeed. 00:10:38.500 --> 00:10:39.180 All right. 00:10:39.180 --> 00:10:42.480 Well, let's start, I guess, start at the top with your article. 00:10:42.480 --> 00:10:45.300 What inspired you, by the way, to write it right now? 00:10:45.300 --> 00:10:46.720 Because it's pretty recent, isn't it? 00:10:46.720 --> 00:10:47.660 Yeah, that's a good question. 00:10:47.660 --> 00:10:53.700 It's not the first time I've been writing content about clean code and stuff. 00:10:53.700 --> 00:11:01.580 In 2016, I actually did a formal certification, building maintainable software from the SIG group. 00:11:01.900 --> 00:11:03.560 Software Improvement Group. 00:11:03.560 --> 00:11:05.120 They have formal certifications. 00:11:05.120 --> 00:11:08.060 And yeah, it's a passion of mine, clean code. 00:11:08.060 --> 00:11:12.540 It's also coming back a lot in the coaching I do day to day, helping people. 00:11:12.540 --> 00:11:14.600 So it's not the first content piece. 00:11:14.600 --> 00:11:19.500 But I think this one kind of summarizes in a bit more of a concise way. 00:11:19.740 --> 00:11:22.420 And of course, there's way much more to it. 00:11:22.420 --> 00:11:25.260 But I think the 10 points here get you pretty far. 00:11:25.260 --> 00:11:27.500 So those are pretty important. 00:11:27.500 --> 00:11:28.180 They sure are. 00:11:28.180 --> 00:11:32.060 So let's start with one that you already kind of laid this out. 00:11:32.060 --> 00:11:35.920 Like so many of these techniques, they are like, they sound so simple. 00:11:35.920 --> 00:11:36.660 And I guess, sure. 00:11:37.220 --> 00:11:43.240 Obviously, Michael, I wouldn't write a 1000 line function. 00:11:43.240 --> 00:11:46.140 And you're like, but it's already 700. 00:11:46.140 --> 00:11:47.640 How did this happen? 00:11:47.640 --> 00:11:47.820 Right? 00:11:47.820 --> 00:11:48.540 How do we get here? 00:11:48.820 --> 00:11:54.140 And the first one solidly falls into that realm, which is smaller units, smaller functions, 00:11:54.140 --> 00:11:58.500 smaller classes, smaller modules, single responsibility principle, all that, right? 00:11:58.500 --> 00:11:59.260 Tell us about this. 00:11:59.380 --> 00:12:04.940 Yeah, so indeed, a function or a unit of code should ideally do one thing. 00:12:04.940 --> 00:12:06.680 And just a side note, right? 00:12:06.680 --> 00:12:08.740 That's usually not how we start. 00:12:08.740 --> 00:12:14.800 Sometimes I do want to make this side note that when we're figuring out a design, it can 00:12:14.800 --> 00:12:18.520 definitely happen that you have very large units because you're basically trying to figure 00:12:18.520 --> 00:12:19.660 out what you're building, right? 00:12:19.660 --> 00:12:21.500 And that's where refactoring comes in. 00:12:21.500 --> 00:12:23.440 But we'll talk about that a bit later. 00:12:23.440 --> 00:12:26.720 But yeah, I give a very simple example in this article, right? 00:12:26.780 --> 00:12:31.960 Where a function parses a CSV file, builds up a result list and also prints it out, right? 00:12:31.960 --> 00:12:37.300 So now this function is doing three things and it probably works and it's fine, but you 00:12:37.300 --> 00:12:41.180 cannot really easily reuse something that's doing three things, right? 00:12:41.180 --> 00:12:45.220 So if you want to plug in this function now into something else, there's a lot of things 00:12:45.220 --> 00:12:49.520 happening that probably doesn't make it a candidate to reuse in its current shape or form. 00:12:49.520 --> 00:12:53.740 It's also harder to test because now you have to test parsing and printing. 00:12:54.140 --> 00:12:59.020 And this is kind of a silly example, but just think about another thing you have in your 00:12:59.020 --> 00:13:00.320 code that's doing multiple things. 00:13:00.320 --> 00:13:03.660 It will just be harder to test because there's a lot more going on. 00:13:03.660 --> 00:13:05.000 And yeah, as you said, right? 00:13:05.000 --> 00:13:09.560 These things sound very intuitive and easy to grasp. 00:13:09.560 --> 00:13:11.400 Yet when we look at code bases, right? 00:13:11.400 --> 00:13:12.640 This happens all the time. 00:13:12.640 --> 00:13:17.440 And yeah, so if something's harder to test, it's harder to guarantee that it works. 00:13:17.440 --> 00:13:21.860 If it's hard to extend and when requirements change, it will be harder to update. 00:13:21.860 --> 00:13:22.420 Yeah. 00:13:22.420 --> 00:13:22.740 Yeah. 00:13:22.740 --> 00:13:23.880 It's harder to maintain. 00:13:23.880 --> 00:13:29.140 It's harder to reason about the more things that it's doing, the more state that it might 00:13:29.140 --> 00:13:29.700 be changing. 00:13:29.700 --> 00:13:31.800 It's harder to onboard new people. 00:13:31.800 --> 00:13:33.540 It's just the whole spectrum. 00:13:35.440 --> 00:13:38.520 This portion of Talk Python Amey is brought to you by TypePy. 00:13:38.520 --> 00:13:42.420 TypePy is the next generation open source Python application builder. 00:13:42.420 --> 00:13:47.480 With TypePy, you can turn data and AI algorithms into full web apps in no time. 00:13:47.480 --> 00:13:48.480 Here's how it works. 00:13:48.480 --> 00:13:51.480 You start with a bare algorithm written in Python. 00:13:51.480 --> 00:13:56.740 You then use TypePy's innovative tool set that enables Python developers to build interactive 00:13:56.740 --> 00:13:58.440 end user applications quickly. 00:13:58.900 --> 00:14:03.000 There's a visual designer to develop highly interactive GUIs ready for production. 00:14:03.000 --> 00:14:07.780 And for inbound data streams, you can program against the TypePy core layer as well. 00:14:07.780 --> 00:14:13.260 TypePy core provides intelligent pipeline management, data caching, and scenario and cycle management 00:14:13.260 --> 00:14:13.780 facilities. 00:14:13.780 --> 00:14:14.860 That's it. 00:14:14.860 --> 00:14:19.940 You'll have transformed a bare algorithm into a full-fledged decision support system for 00:14:19.940 --> 00:14:20.460 end users. 00:14:20.460 --> 00:14:23.260 TypePy is pure Python and open source. 00:14:23.260 --> 00:14:25.820 And you install it with a simple pip install TypePy. 00:14:26.340 --> 00:14:30.400 For large organizations that need fine-grained control and authorization around their data, 00:14:30.400 --> 00:14:32.800 there is a paid TypePy Enterprise Edition. 00:14:32.800 --> 00:14:36.640 But the TypePy core and GUI described above is completely free to use. 00:14:36.640 --> 00:14:41.720 Learn more and get started by visiting talkpython.fm/taipy. 00:14:41.720 --> 00:14:43.400 That's T-A-I-P-Y. 00:14:43.400 --> 00:14:44.700 The link's in your show notes. 00:14:44.700 --> 00:14:47.540 Thank you to TypePy for sponsoring the show. 00:14:47.540 --> 00:14:55.060 And it's write functions that are 10 lines long, not 100 lines long. 00:14:55.320 --> 00:14:59.320 Now, I'd like to hear your thoughts on this, but my feeling about all of this stuff is, 00:14:59.320 --> 00:15:02.260 as a general rule, this is what you should do. 00:15:02.260 --> 00:15:06.640 There will be situations where you might, you know, this is just, I can't think of something 00:15:06.640 --> 00:15:06.940 better. 00:15:06.940 --> 00:15:12.320 Or it's way over the top to try to, like, adhere to all of these rules within this small 00:15:12.320 --> 00:15:12.880 context. 00:15:12.880 --> 00:15:18.200 I could tell you, like, on the Talk Python training website, there's a couple of places where 00:15:18.200 --> 00:15:22.900 it's like 75, 80, 90 lines of code for a single function. 00:15:22.900 --> 00:15:24.840 I'm just like, this is so bad. 00:15:24.840 --> 00:15:29.760 I just, I wish it wasn't like this, but it's just weirdly unique. 00:15:29.760 --> 00:15:35.420 And, but there's, you know, 19,000 other lines of code that are all three lines, five lines 00:15:35.420 --> 00:15:36.460 type of thing. 00:15:36.460 --> 00:15:36.680 Right? 00:15:36.740 --> 00:15:41.040 So it's, for me, at least, this isn't a 100% or you're doing it wrong. 00:15:41.040 --> 00:15:45.400 It's a 98% or 95% of the time you should be doing this. 00:15:45.400 --> 00:15:46.680 There may be some weird case. 00:15:46.680 --> 00:15:47.560 And I don't know. 00:15:47.560 --> 00:15:49.940 What do you, how do you feel about that in general on these topics? 00:15:50.140 --> 00:15:54.500 Yeah, as I said before, sometimes you just don't get the design right from the start. 00:15:54.500 --> 00:15:58.200 So inevitably you're going to write some longer classes or functions. 00:15:58.200 --> 00:16:02.540 But then when you break them out in smaller units, the other thing I have to say about 00:16:02.540 --> 00:16:05.420 that is it gives you an opportunity to better documents. 00:16:05.420 --> 00:16:10.500 Because in this example, if you break this long function that's doing three things out 00:16:10.500 --> 00:16:15.740 into three separate functions, parse CSV, buildup list, bad name, but you get the point, 00:16:16.040 --> 00:16:20.500 and print results, then all of a sudden we have three units now and every unit has a 00:16:20.500 --> 00:16:20.800 name. 00:16:20.800 --> 00:16:25.360 Hence, when you go back after a year and look at that code, which always happens and you 00:16:25.360 --> 00:16:27.300 always wonder, what the heck was I thinking? 00:16:27.300 --> 00:16:33.360 Now you add a glance just by looking at the function numbers, you have just already a better 00:16:33.360 --> 00:16:33.800 idea. 00:16:33.800 --> 00:16:36.320 These functions, you can give doc strings as well. 00:16:36.320 --> 00:16:41.020 So at a glance, you have just a much easier time figuring out what this was about. 00:16:41.020 --> 00:16:44.940 Yeah, I appreciate you actually gave a shout out to me in this first piece here, which 00:16:44.940 --> 00:16:45.660 I didn't expect. 00:16:45.660 --> 00:16:50.720 But one of my rules, you know, and I see in this article, you referenced Martin Fowler's 00:16:50.720 --> 00:16:51.420 refactoring book. 00:16:51.420 --> 00:16:54.800 And one of the most important things that came out of that is not all the refactorings, but 00:16:54.800 --> 00:16:56.780 this idea of code smells, right? 00:16:56.780 --> 00:17:00.040 And maybe tell people real quick about code smells. 00:17:00.040 --> 00:17:02.120 Yeah, that's a funny name, right? 00:17:02.120 --> 00:17:02.760 Code smell. 00:17:02.760 --> 00:17:03.260 It is. 00:17:03.260 --> 00:17:06.400 Code that is smelling and this analogy I came up with. 00:17:06.400 --> 00:17:13.380 But yeah, basically it's code that's not following these best practices and it's just not maintainable, 00:17:13.380 --> 00:17:16.580 not easy to extend, going back to these principles we mentioned. 00:17:16.580 --> 00:17:18.720 So yeah, not following these guidelines. 00:17:18.720 --> 00:17:20.320 That code can be smelly. 00:17:20.320 --> 00:17:21.660 It can be as code smell. 00:17:21.660 --> 00:17:22.160 Yeah. 00:17:22.160 --> 00:17:22.440 Yeah. 00:17:22.440 --> 00:17:24.920 Well, the idea is like, it's not actually not working. 00:17:24.920 --> 00:17:26.200 It's just not nice. 00:17:26.200 --> 00:17:30.500 You know, you kind of turn your nose up at it when you see it, but it's, you can't say it's 00:17:30.500 --> 00:17:32.060 broken because it is working. 00:17:32.740 --> 00:17:33.300 It's a good point. 00:17:33.300 --> 00:17:35.160 It smells a little bit off, right? 00:17:35.160 --> 00:17:38.800 It's not quite broken code, but it's sour. 00:17:38.800 --> 00:17:39.360 I don't know. 00:17:39.360 --> 00:17:44.640 And so the reason I bring this up is one of my rules of thumb here that I love, and I think 00:17:44.640 --> 00:17:47.500 you're kind of hinting that with this little shout out that you gave me in this article 00:17:47.500 --> 00:17:53.460 is when we come across these code smells often, especially when you're earlier in your career, 00:17:53.460 --> 00:17:58.020 often the reaction or the first thought is, you know, this part is not nice. 00:17:58.020 --> 00:17:59.240 This part is complicated. 00:17:59.240 --> 00:18:01.240 This part is hard to maintain or hard to understand. 00:18:01.400 --> 00:18:02.800 So I need to put a nice comment. 00:18:02.800 --> 00:18:04.480 I've been told, comment your code. 00:18:04.480 --> 00:18:05.180 Don't be a jerk. 00:18:05.180 --> 00:18:05.700 Comment it. 00:18:05.700 --> 00:18:09.660 So I'm going to put a big comment that describes why it's really bad and all that. 00:18:09.660 --> 00:18:15.980 And in the code smells sort of world, these code comments can be seen as deodorant for 00:18:15.980 --> 00:18:16.460 the smell. 00:18:16.460 --> 00:18:19.340 Like it doesn't remove the smell, but it kind of obscures. 00:18:19.340 --> 00:18:25.480 Like it's not as bad if you saw the comment saying why the code that follows is bad, but maybe 00:18:25.480 --> 00:18:27.720 you could just make it not need a comment. 00:18:27.720 --> 00:18:32.900 And a lot of times, like you just said, that's, well, these five lines of code need an explanation 00:18:32.900 --> 00:18:34.400 because they're mixed in with all this. 00:18:34.400 --> 00:18:39.640 But if they had a function that had a name, whose name was basically the comment, well, 00:18:39.640 --> 00:18:43.080 then you don't need a comment because the name is the comment and it's now small and understandable, 00:18:43.080 --> 00:18:43.440 right? 00:18:43.440 --> 00:18:45.940 Like there's a lot of these little iterative things that go on. 00:18:46.180 --> 00:18:46.580 Exactly. 00:18:46.580 --> 00:18:46.840 Yeah. 00:18:46.840 --> 00:18:47.620 That's a great point. 00:18:47.620 --> 00:18:52.580 And it's, it's very easy to make that refactoring, just turn the comment into a function and we 00:18:52.580 --> 00:18:53.760 have created another unit. 00:18:53.760 --> 00:18:55.600 We can extend, we can test, et cetera. 00:18:55.600 --> 00:18:59.400 So yeah, it's interesting because there are kind of mixed feelings about commands. 00:18:59.400 --> 00:19:01.720 Some people say, voracious, command your code. 00:19:01.720 --> 00:19:06.480 But mostly in their literature, I'm reading that commands are actually not that good. 00:19:06.480 --> 00:19:10.940 And sometimes even labeled as a code smell in the sense that your code should be kind of 00:19:10.940 --> 00:19:11.280 intuitive. 00:19:11.280 --> 00:19:15.400 I think it's going back to that, like half of the time when people are actually putting 00:19:15.400 --> 00:19:19.920 those comments, it's because there's something kind of messy and they're trying to help you 00:19:19.920 --> 00:19:23.800 get over that mess or deal with that mess rather than just fixing the mess, you know? 00:19:23.800 --> 00:19:24.100 Yeah. 00:19:24.100 --> 00:19:26.220 It might be an indication of a bad design, right? 00:19:26.220 --> 00:19:27.000 Yes, exactly. 00:19:27.000 --> 00:19:28.760 So you might even have to go back to the drawing board. 00:19:28.760 --> 00:19:29.240 Yeah. 00:19:29.240 --> 00:19:33.840 But that said, I definitely see a place for commands where sometimes you just want to remind 00:19:33.840 --> 00:19:37.500 yourself and of course your team members, not what the code is. 00:19:37.500 --> 00:19:41.160 They can read the code obviously, but why you took that decision, what the, 00:19:41.160 --> 00:19:44.580 and there might just be some extra context that you need to give. 00:19:44.580 --> 00:19:44.900 Yeah. 00:19:44.900 --> 00:19:48.400 And it's also different than doc strings potentially, right? 00:19:48.400 --> 00:19:53.780 Which is kind of a form of a comment, but it's meant to talk about the API and not cover 00:19:53.780 --> 00:19:55.620 up some weird thing you had to do in the middle. 00:19:55.620 --> 00:19:56.040 Exactly. 00:19:56.040 --> 00:19:56.380 Yeah. 00:19:56.380 --> 00:19:59.280 Doc strings are basically your API documentation. 00:19:59.280 --> 00:19:59.820 Yeah. 00:19:59.820 --> 00:20:00.720 Yeah, exactly. 00:20:00.720 --> 00:20:01.520 All right. 00:20:01.520 --> 00:20:03.720 Well, good, good stuff. 00:20:03.720 --> 00:20:07.720 I mean, even GitHub Copilot and those things are starting to use these comments as a way to 00:20:07.720 --> 00:20:11.420 say, well, I'll just make a function that kind of is named what the comment is. 00:20:11.420 --> 00:20:18.180 You know, so it's even our robot overlords are going to, going to help us by taking these 00:20:18.180 --> 00:20:20.260 comments and removing them, putting the functions there. 00:20:20.260 --> 00:20:22.000 Help us not replace us, right? 00:20:22.000 --> 00:20:22.940 Yeah. 00:20:22.940 --> 00:20:23.640 Hopefully. 00:20:23.640 --> 00:20:24.260 Fingers crossed. 00:20:24.420 --> 00:20:29.740 Another thing related to this, strongly related to this, because the more things you have 00:20:29.740 --> 00:20:32.540 that are smaller units, you're probably still going to have about the same amount of codes. 00:20:32.540 --> 00:20:36.240 You have more functions, more classes, more modules, files, and so on. 00:20:36.240 --> 00:20:39.380 What gets tricky can be naming them, right? 00:20:39.380 --> 00:20:44.760 So choosing good names also, I think, probably is a message in here that people need to think 00:20:44.760 --> 00:20:44.980 about. 00:20:44.980 --> 00:20:45.840 What are your thoughts on that? 00:20:45.840 --> 00:20:46.740 Yeah, it's funny. 00:20:46.740 --> 00:20:51.820 Again, another thing that sounds very intuitive, but wasn't there a saying like there are two 00:20:51.820 --> 00:20:53.920 or three complex problems in science. 00:20:53.920 --> 00:20:56.680 One other one I'm going to remember and naming things. 00:20:56.680 --> 00:20:57.640 Yeah. 00:20:57.640 --> 00:21:00.960 There's two problems that are hard in computer science. 00:21:00.960 --> 00:21:04.620 Naming things, cache and validation, and off by one errors. 00:21:04.620 --> 00:21:05.460 Thank you. 00:21:05.460 --> 00:21:05.840 Yeah. 00:21:05.840 --> 00:21:07.840 So naming is up there, right? 00:21:07.840 --> 00:21:08.780 It is. 00:21:08.780 --> 00:21:09.060 That's right. 00:21:09.060 --> 00:21:12.900 I think it goes back again to knowing your design and what you're building. 00:21:12.900 --> 00:21:15.080 And sometimes you don't really have that figured out. 00:21:15.080 --> 00:21:16.720 Hence, naming becomes more difficult. 00:21:16.720 --> 00:21:18.420 But I think that's an experience thing. 00:21:18.500 --> 00:21:21.420 You get better at it the more code you write. 00:21:21.420 --> 00:21:24.200 Maybe we can touch on the magic numbers there. 00:21:24.200 --> 00:21:24.980 Yeah, absolutely. 00:21:24.980 --> 00:21:26.660 That's the next one is magic numbers. 00:21:26.660 --> 00:21:31.540 And magic, the number part, I think, could be expanded a little bit broader even. 00:21:31.540 --> 00:21:34.260 You know, magic, static values, right? 00:21:34.260 --> 00:21:40.880 But if you see 360, you know, think just in the code, like, well, is that like a degrees? 00:21:40.880 --> 00:21:41.280 Right. 00:21:41.280 --> 00:21:41.960 What is that? 00:21:41.960 --> 00:21:43.820 Probably degrees, but it might not be. 00:21:43.820 --> 00:21:44.300 I don't know. 00:21:44.300 --> 00:21:45.340 So yeah, magic numbers. 00:21:45.340 --> 00:21:46.500 That's your next recommendation. 00:21:46.500 --> 00:21:48.420 I'm presuming to avoid them. 00:21:48.420 --> 00:21:48.820 Yes. 00:21:48.820 --> 00:21:54.700 So when you see some sort of random integer in the code, which might be an intuitive one, 00:21:54.700 --> 00:21:59.500 like 365 number of days in a year, which we might kind of guess. 00:21:59.500 --> 00:22:02.360 But yeah, any guessing in code is not good. 00:22:02.600 --> 00:22:10.340 So it's very easy to then replace that 365 integer with a number on the score of days in a year 00:22:10.340 --> 00:22:11.120 or something like that. 00:22:11.120 --> 00:22:12.680 Something that expresses meaning. 00:22:12.680 --> 00:22:13.240 Yeah. 00:22:13.240 --> 00:22:15.180 And again, this is kind of an obvious example. 00:22:15.180 --> 00:22:20.100 But if you have some magic five or six or 87 in there, the reader of this code probably 00:22:20.100 --> 00:22:21.140 doesn't know what that means. 00:22:21.140 --> 00:22:21.480 Right. 00:22:21.540 --> 00:22:26.600 So if you have a constant uppercase with underscores as per PEP 8 defined at the top 00:22:26.600 --> 00:22:29.300 of your module, I usually put them in the top of the module. 00:22:29.300 --> 00:22:34.020 And then in the code, you see like max underscore, blah, blah, blah, a real name. 00:22:34.020 --> 00:22:36.260 And then immediately makes sense. 00:22:36.260 --> 00:22:36.760 Right. 00:22:36.840 --> 00:22:41.100 And it's also a nice way of grouping those variables in one place. 00:22:41.100 --> 00:22:42.160 I said top of the module. 00:22:42.160 --> 00:22:47.000 But if you have many, you could also have a constants.py in your package to group them. 00:22:47.000 --> 00:22:53.780 You can also use enums to group various constants together if they logically pertain to the same 00:22:53.780 --> 00:22:54.000 group. 00:22:54.000 --> 00:22:55.580 And again, all more readable. 00:22:55.580 --> 00:22:56.200 Yeah. 00:22:56.200 --> 00:23:00.260 Enums are a great recommendation because instead of saying, well, the default Sunday, so we're 00:23:00.260 --> 00:23:01.240 just going to put Sunday here. 00:23:01.240 --> 00:23:02.920 Oh, why is Sunday here? 00:23:02.920 --> 00:23:03.440 This is weird. 00:23:03.780 --> 00:23:07.840 Or you say the function can take a string when really it can only take seven strings, 00:23:07.840 --> 00:23:10.000 seven particular values of string. 00:23:10.000 --> 00:23:10.420 Right. 00:23:10.420 --> 00:23:15.300 You could really clearly communicate that with enums, which is quite nice. 00:23:15.300 --> 00:23:15.640 Yeah. 00:23:15.640 --> 00:23:16.720 And the use of constants. 00:23:16.720 --> 00:23:17.740 That's really a win. 00:23:17.740 --> 00:23:19.820 I'm 100% on board with you on constants. 00:23:19.820 --> 00:23:25.420 All caps, maybe snake case, otherwise, you know, underscores, separate them. 00:23:25.420 --> 00:23:30.600 But I have tooling that I work with all the time that'll say, oh no, you misnamed this variable. 00:23:30.600 --> 00:23:33.640 Python, you know, they want to use lowercase variables, not uppercase 00:23:33.640 --> 00:23:33.980 variables. 00:23:33.980 --> 00:23:36.380 I'm like, but for constants, they say to use uppercase. 00:23:36.380 --> 00:23:37.280 Why don't you know this? 00:23:37.280 --> 00:23:38.040 It drives me crazy. 00:23:38.040 --> 00:23:41.380 So I was thinking about sort of expanding on this a little bit. 00:23:41.380 --> 00:23:47.540 Are you familiar with this, the typing.final when this was added in 3.8? 00:23:47.540 --> 00:23:48.780 Recently discovered that. 00:23:48.780 --> 00:23:49.240 Yes. 00:23:49.240 --> 00:23:50.280 Super nice. 00:23:50.280 --> 00:23:56.220 So it's also the idea is that it comes along and is meant to be used in this scenario in 00:23:56.220 --> 00:23:59.220 addition to what we've already discussed. 00:23:59.400 --> 00:24:04.840 So the example in the Python docs says there's a max size, capital max, capital size. 00:24:04.840 --> 00:24:09.520 Instead of just saying it's 9,000, you say it's colon final 9,000. 00:24:09.520 --> 00:24:12.580 Now that means nothing to Python. 00:24:12.580 --> 00:24:13.960 It means nothing. 00:24:14.140 --> 00:24:16.340 But it means something to type checkers, right? 00:24:16.340 --> 00:24:22.180 So if you have like mypy or something and somebody tries to change the value of it later, it's 00:24:22.180 --> 00:24:27.080 going to come at least as a linting type of error, if not a full on runtime error. 00:24:27.080 --> 00:24:30.000 So this is something people could leverage to go a little bit further. 00:24:30.000 --> 00:24:31.740 That's super nice type hinting. 00:24:31.740 --> 00:24:35.740 As you will paraphrase, it's meaningless to Python. 00:24:35.740 --> 00:24:40.920 But if you now run your checker and it's somewhere in your code that you try to overwrite that 00:24:40.920 --> 00:24:42.800 variable, which is perfectly fine, right? 00:24:42.800 --> 00:24:46.800 Because Python doesn't enforce, doesn't say anything if you now would assign a new value 00:24:46.800 --> 00:24:47.520 to max size. 00:24:47.520 --> 00:24:49.960 But there is no constant Python. 00:24:49.960 --> 00:24:50.440 Yeah. 00:24:50.440 --> 00:24:51.960 Mypy picks up on that final. 00:24:51.960 --> 00:24:52.960 Hey, it was final. 00:24:52.960 --> 00:24:54.120 Shouldn't overwrite that. 00:24:54.260 --> 00:24:55.540 So super powerful. 00:24:55.540 --> 00:24:56.660 I should use this more. 00:24:56.660 --> 00:24:57.060 Yeah. 00:24:57.060 --> 00:24:57.340 Yeah. 00:24:57.340 --> 00:25:01.420 And so you can say final or I would think preferably final of int. 00:25:01.420 --> 00:25:04.580 So you say what type it actually is in addition to that. 00:25:04.580 --> 00:25:10.580 Now related to this, related to this is it's not exactly a magic number, but I often find 00:25:10.580 --> 00:25:13.620 magic numbers appearing in this situation. 00:25:13.620 --> 00:25:20.100 And that has to do with, I want this thing to have maybe a default value or a value that 00:25:20.100 --> 00:25:21.880 says clearly communicates. 00:25:21.880 --> 00:25:24.240 I haven't set a value for it, but I want it to be. 00:25:24.240 --> 00:25:26.760 Like in this case, a number, it still needs to be an int. 00:25:26.760 --> 00:25:28.480 Well, what integer are you going to put there? 00:25:28.480 --> 00:25:28.900 Hmm. 00:25:28.900 --> 00:25:29.920 Zero. 00:25:29.920 --> 00:25:31.620 Well, zero valid value. 00:25:31.620 --> 00:25:32.780 Do you want it to be falsy? 00:25:32.780 --> 00:25:34.660 Like there's all, could it be negative? 00:25:34.660 --> 00:25:35.980 Which negative values? 00:25:35.980 --> 00:25:37.300 And then you see weird tests. 00:25:37.300 --> 00:25:39.920 Like if it's less than zero, you're like, why is it testing that? 00:25:39.920 --> 00:25:40.980 Well, that means it's not set. 00:25:40.980 --> 00:25:42.340 Like, okay, that's weird. 00:25:42.800 --> 00:25:48.840 So another idea that I think comes in that's pretty interesting is the sentinel pattern where 00:25:48.840 --> 00:25:54.140 you come up with a particular number and sort of store that and say this number or value, 00:25:54.140 --> 00:26:00.340 something you say, if it is this, that means it's unset or it's just a weird case or it's, 00:26:00.340 --> 00:26:01.900 it's kind of like setting it to none. 00:26:02.000 --> 00:26:06.320 But if that's not going to be a case you can use, sometimes none is, is that thing. 00:26:06.320 --> 00:26:06.740 Right. 00:26:06.740 --> 00:26:08.240 But not always. 00:26:08.240 --> 00:26:09.280 Are you familiar with this? 00:26:09.280 --> 00:26:10.280 Do you do anything like this? 00:26:10.280 --> 00:26:11.680 I have not really used it. 00:26:11.680 --> 00:26:13.740 So I had to read a read up on it. 00:26:13.740 --> 00:26:19.840 I think I use none quite a bit, but I think the, I mean, that's at least better maybe than 00:26:19.840 --> 00:26:22.260 minus one is the find example at the top. 00:26:22.260 --> 00:26:22.660 Yeah. 00:26:22.840 --> 00:26:27.240 But I think this even wins by being more explicit even, right? 00:26:27.240 --> 00:26:29.400 By having an object then to test against. 00:26:29.400 --> 00:26:29.820 Yeah. 00:26:29.820 --> 00:26:36.880 So one example of a standard library is the config parser has a underscore unset as a global variable 00:26:36.880 --> 00:26:38.880 and that's its, its sentinel value. 00:26:38.880 --> 00:26:45.540 BZ2 has the underscore sentinel to just call out the pattern directly there and so on. 00:26:45.540 --> 00:26:51.300 My favorite one out of this actually is a variation is this, this null object pattern. 00:26:51.800 --> 00:26:56.460 So null, because it comes, you know, sort of earlier in the life cycle of languages where 00:26:56.460 --> 00:27:01.920 null, not none, but where a lot of times if you see if this value is none, then we can 00:27:01.920 --> 00:27:05.300 do a thing other than otherwise we can do actually work with it. 00:27:05.300 --> 00:27:05.480 Right. 00:27:05.480 --> 00:27:08.100 And you'll see that these, these tests all over. 00:27:08.100 --> 00:27:14.880 And so this pattern is come up with a sentinel value that is not none, but kind of behaves 00:27:14.880 --> 00:27:16.700 in a no op way. 00:27:16.700 --> 00:27:17.280 Right. 00:27:17.280 --> 00:27:21.720 So you could give it a value of a person who is a sentinel and it just, if you try to 00:27:21.720 --> 00:27:24.960 get his name, it's just going to return, I don't know, nothing or something like that. 00:27:24.960 --> 00:27:25.400 Right. 00:27:25.400 --> 00:27:29.920 So you can, if it makes sense in that situation, you could remove a lot of these, if thing is 00:27:29.920 --> 00:27:34.260 none, do something else, do something else just globally, which is really nice. 00:27:34.260 --> 00:27:36.660 So you don't have to do this non check here. 00:27:36.660 --> 00:27:38.820 So are you saving an if else? 00:27:38.820 --> 00:27:39.140 Yeah. 00:27:39.140 --> 00:27:41.560 You're saving, you're saving the cyclomatic complexity. 00:27:41.560 --> 00:27:47.020 You're saving like branching at the cost of maybe allocating more stuff or, or having it 00:27:47.020 --> 00:27:50.360 possibly have this value that doesn't really mean it has a value, you know? 00:27:50.380 --> 00:27:52.320 So you got to trade it off and figure out what it makes. 00:27:52.320 --> 00:27:55.220 That's interesting because I think I do the is none quite a bit. 00:27:55.220 --> 00:28:00.340 So yeah, I do too, because sometimes it's kind of hard to deal with that or you don't control 00:28:00.340 --> 00:28:00.440 it. 00:28:00.440 --> 00:28:05.940 A lot of times kind of going back to when I was talking before about the 95% case and I told 00:28:05.940 --> 00:28:07.660 you about this really gnarly bit of code. 00:28:07.660 --> 00:28:12.220 that's because I'm consuming two other APIs that I have no control over and they're junky. 00:28:12.220 --> 00:28:13.160 They're real junky. 00:28:13.160 --> 00:28:18.000 So, you know, I've kind of got to like fit it together and, and you don't get a pick whether 00:28:18.000 --> 00:28:20.080 they use the null object pattern or not. 00:28:20.080 --> 00:28:21.140 You just got to make it work. 00:28:21.140 --> 00:28:21.380 Right. 00:28:21.380 --> 00:28:21.580 Yeah. 00:28:21.580 --> 00:28:22.060 That's a good point. 00:28:22.060 --> 00:28:22.580 Yeah. 00:28:22.580 --> 00:28:22.840 Yeah. 00:28:22.840 --> 00:28:23.280 Indeed. 00:28:23.280 --> 00:28:24.060 All right. 00:28:24.060 --> 00:28:28.220 So those are all kind of under the magic number category, I would say, even though technically 00:28:28.220 --> 00:28:29.980 some of them are not, like I said, not numbers. 00:28:29.980 --> 00:28:34.480 This one, honestly, I'll tell you, you asked me about kind of my first experiences with Python 00:28:34.480 --> 00:28:35.000 long ago. 00:28:35.000 --> 00:28:39.700 And this one weirded me out a little bit because it's something I had spent a long time in C, 00:28:39.700 --> 00:28:43.420 C++, C#, trying to just remove and weed out. 00:28:43.420 --> 00:28:44.460 And that's global scope. 00:28:44.460 --> 00:28:46.940 Tell us about this and maybe why to watch out for it. 00:28:47.160 --> 00:28:52.340 If we leave something in global scope, for example, we have a global variable and we're 00:28:52.340 --> 00:28:58.040 pulling that into a function with a global keyword and we're making changes to it. 00:28:58.040 --> 00:29:00.540 Now this function has side effects, right? 00:29:00.540 --> 00:29:05.880 So you have the stuff that's going in the function, but it's also mutating some external object, 00:29:05.880 --> 00:29:06.300 right? 00:29:06.300 --> 00:29:11.340 And when you write it, you probably are very aware of it because you're doing it, but you're 00:29:11.340 --> 00:29:13.900 going back and all of a sudden this might bite you. 00:29:13.900 --> 00:29:15.000 It will surprise you. 00:29:15.000 --> 00:29:16.980 Side effects overall are bad, right? 00:29:17.040 --> 00:29:20.780 And the global scope has that potential because it's global scope. 00:29:20.780 --> 00:29:24.160 It's not local scope to some class or function. 00:29:24.160 --> 00:29:24.680 Yeah. 00:29:24.680 --> 00:29:29.840 Basically that, that, it can lead to surprises and we don't want surprises in code. 00:29:29.840 --> 00:29:30.140 Yeah. 00:29:30.140 --> 00:29:32.480 And it's not an argument you pass to a function. 00:29:32.480 --> 00:29:34.700 It's not a return value from a function. 00:29:34.700 --> 00:29:38.060 You might not even know that that is in play as you interact with part of your code, but 00:29:38.060 --> 00:29:42.000 somewhere out there, it's something deep down is reaching up and seeing that value. 00:29:44.460 --> 00:29:47.600 This portion of talk Python to me is brought to you by brilliant.org. 00:29:47.600 --> 00:29:50.580 You're a curious person who loves to learn about technology. 00:29:50.580 --> 00:29:52.520 I know because you're listening to my show. 00:29:52.520 --> 00:29:57.260 That's why you would also be interested in this episode's sponsor, brilliant.org. 00:29:57.260 --> 00:30:00.400 Brilliant.org is entertaining, engaging, and effective. 00:30:00.620 --> 00:30:05.340 If you're like me and feel that binging yet another sitcom series is kind of missing out 00:30:05.340 --> 00:30:09.760 on life, then how about spending 30 minutes a day getting better at programming or deepening 00:30:09.760 --> 00:30:14.420 your knowledge and foundations of topics you've always wanted to learn better like chemistry 00:30:14.420 --> 00:30:16.220 or biology over on brilliant. 00:30:16.220 --> 00:30:22.660 Brilliant has thousands of lessons from foundational and advanced math to data science, algorithms, 00:30:22.660 --> 00:30:25.620 neural networks, and more with new lessons added monthly. 00:30:25.860 --> 00:30:29.920 When you sign up for a free trial, they ask a couple of questions about what you're interested 00:30:29.920 --> 00:30:31.640 in as well as your background knowledge. 00:30:31.640 --> 00:30:35.520 Then you're presented with a cool learning path to get you started right where you should be. 00:30:35.520 --> 00:30:38.580 Personally, I'm going back to some science foundations. 00:30:38.580 --> 00:30:41.980 I love chemistry and physics, but haven't touched them for 20 years. 00:30:41.980 --> 00:30:48.540 So I'm looking forward to playing with PV equals NRT, you know, the ideal gas law, and all 00:30:48.540 --> 00:30:50.000 the other foundations of our world. 00:30:50.440 --> 00:30:55.520 With Brilliant, you'll get hands-on on a whole universe of concepts in math, science, computer 00:30:55.520 --> 00:30:59.500 science, and solve fun problems while growing your critical thinking skills. 00:30:59.500 --> 00:31:02.120 Of course, you could just visit brilliant.org directly. 00:31:02.120 --> 00:31:04.100 Its URL is right there in the name, isn't it? 00:31:04.100 --> 00:31:09.920 But please use our link because you'll get something extra, 20% off an annual premium subscription. 00:31:09.920 --> 00:31:15.140 So sign up today at talkpython.fm/brilliant and start a seven-day free trial. 00:31:15.140 --> 00:31:17.440 That's talkpython.fm/brilliant. 00:31:17.620 --> 00:31:19.420 The link is in your podcast player show notes. 00:31:19.420 --> 00:31:21.840 Thank you to brilliant.org for supporting the show. 00:31:21.840 --> 00:31:28.480 You know, one of the areas where this comes back, where I think maybe things might have 00:31:28.480 --> 00:31:32.840 been different if the people were able to see the future 30 years in advance, which I'm not 00:31:32.840 --> 00:31:37.500 expecting they should be able to, would be the global interpreter lock itself with its global 00:31:37.500 --> 00:31:39.800 description right there. 00:31:39.800 --> 00:31:40.920 It's first G, you know? 00:31:41.300 --> 00:31:47.600 You know, Eric Snow did a lot of work to try to create a per sub-interpreter lock. 00:31:47.600 --> 00:31:51.700 So it's still a global lock, but global for that sub-interpreter and try to share those 00:31:51.700 --> 00:31:52.400 within processes. 00:31:52.400 --> 00:31:58.720 And I recall I talked about just reworking hundreds or thousands of global variables so that they 00:31:58.720 --> 00:32:01.620 were no longer globally shared, but were more local. 00:32:01.800 --> 00:32:06.860 And it's this kind of stuff that can grow and really makes it hard to go forward and make 00:32:06.860 --> 00:32:07.400 changes. 00:32:07.400 --> 00:32:07.700 Yeah. 00:32:07.700 --> 00:32:08.140 Interesting. 00:32:08.140 --> 00:32:12.560 I think you have had an episode on the GIL and then the refactoring, right? 00:32:12.560 --> 00:32:13.220 Yes. 00:32:13.220 --> 00:32:14.100 A couple. 00:32:14.100 --> 00:32:19.960 I have not had Sam Gross on for his, his like true gill-less Python work, but he's welcome 00:32:19.960 --> 00:32:21.000 anytime he wants to come. 00:32:21.000 --> 00:32:21.500 Of course. 00:32:21.500 --> 00:32:21.760 Cool. 00:32:21.880 --> 00:32:22.100 All right. 00:32:22.100 --> 00:32:22.720 Let me see. 00:32:22.720 --> 00:32:25.000 I want to make sure I don't skip my, anything on my list. 00:32:25.000 --> 00:32:27.180 So let me just throw this out here for you. 00:32:27.180 --> 00:32:30.960 So global scope says, look, you should avoid having global variables. 00:32:30.960 --> 00:32:34.000 Sometimes you'll need global variables, but they shouldn't be the default. 00:32:34.000 --> 00:32:38.500 Is there a way you can pass this down to the thing that needs it and not just make it global 00:32:38.500 --> 00:32:39.880 and shared and right. 00:32:39.880 --> 00:32:43.640 So minimize what is global, I guess, is one of the things. 00:32:43.640 --> 00:32:49.120 When I first saw that, well, Python is full of just a bunch of modules and functions and 00:32:49.120 --> 00:32:51.200 the shared state is going to end up in these global variables. 00:32:51.300 --> 00:32:52.720 And that seems really, oh my gosh. 00:32:52.720 --> 00:32:58.720 But if you look at languages like Java, C#, C++, you end up with a lot of static 00:32:58.720 --> 00:32:59.340 classes. 00:32:59.340 --> 00:33:05.200 And just because there's a class namespace between your global variable and not, they're 00:33:05.200 --> 00:33:06.080 the same thing. 00:33:06.080 --> 00:33:06.520 Right. 00:33:06.520 --> 00:33:11.860 And so modules and module level variables are very, there's something that you don't want 00:33:11.860 --> 00:33:17.100 to have too many of, but they're not as out of whack with the rest of programming as 00:33:17.100 --> 00:33:19.440 I think maybe people might initially see them are. 00:33:19.440 --> 00:33:20.020 Right. 00:33:20.080 --> 00:33:24.500 There's no real difference between a static class and a function and a global variable 00:33:24.500 --> 00:33:25.120 and a module. 00:33:25.120 --> 00:33:26.860 Because there's scope to that module. 00:33:26.860 --> 00:33:27.360 Right. 00:33:27.360 --> 00:33:31.140 So unless you bring in that module, you don't have access to it. 00:33:31.140 --> 00:33:31.540 You mean? 00:33:31.540 --> 00:33:32.360 Yeah, exactly. 00:33:32.360 --> 00:33:37.200 And if, if you have a class and it has one value and if you have a module as one value, 00:33:37.200 --> 00:33:40.180 it's really like, it's really semantics on whether they're different. 00:33:40.420 --> 00:33:44.480 So I don't feel like putting them in, you know, some languages I'm maybe thinking like, oh, 00:33:44.480 --> 00:33:46.940 well, we don't have that because we have classes and we put stuff in class. 00:33:46.940 --> 00:33:49.100 Like if they're static classes, so the same thing. 00:33:49.100 --> 00:33:49.360 Yeah. 00:33:49.360 --> 00:33:55.180 Sometimes what confuses people though is, is having a static method or just a plain function 00:33:55.180 --> 00:33:56.940 outside of the class. 00:33:56.940 --> 00:34:02.520 And I've been a long time proponent of just a function, but I did see a Raymond Hattinger 00:34:02.520 --> 00:34:08.340 talk where he showed that if you do now, if you have the static method, so you bring basically 00:34:08.340 --> 00:34:15.000 the function in the class without it handling the instance, it does show it as part of your 00:34:15.000 --> 00:34:15.340 API. 00:34:15.580 --> 00:34:19.840 So if you now do a DURL on an instance of that class, that static method shows up, which 00:34:19.840 --> 00:34:21.080 I found kind of interesting. 00:34:21.080 --> 00:34:22.180 That is interesting. 00:34:22.180 --> 00:34:22.680 Yeah. 00:34:22.680 --> 00:34:26.900 I think there's a lot of places where people think I need a static class or, or something 00:34:26.900 --> 00:34:30.360 where it could just be a module with functions and maybe a global variable or two. 00:34:30.360 --> 00:34:34.500 But if you do have classes and I guess, and you're trying to look what's part of this class, 00:34:34.500 --> 00:34:37.040 then making that, go ahead and bringing that into the class. 00:34:37.040 --> 00:34:37.980 That totally makes sense to me. 00:34:37.980 --> 00:34:38.680 I can see that. 00:34:38.680 --> 00:34:40.620 I didn't see that presentation, but that makes sense. 00:34:40.620 --> 00:34:40.820 Yeah. 00:34:40.820 --> 00:34:44.780 As a form of grouping, but I'm with you with modules and functions. 00:34:44.940 --> 00:34:45.800 It can get very far. 00:34:45.800 --> 00:34:50.960 I would say more people error on trying to build up stuff into a bunch of classes because 00:34:50.960 --> 00:34:55.860 they've seen that in other languages they're coming from, then they don't quite group it 00:34:55.860 --> 00:34:56.140 right. 00:34:56.140 --> 00:35:00.800 You know, like it's, it's more of not idiomatic code, which I guess we're going to get to as 00:35:00.800 --> 00:35:01.860 well as some of the other stuff. 00:35:01.860 --> 00:35:07.420 So one of the things that we kicked off this conversation with is, well, you've, you said 00:35:07.420 --> 00:35:08.060 we were spoiled. 00:35:08.060 --> 00:35:09.460 I take offense to that. 00:35:09.460 --> 00:35:11.940 I think it's absolutely fair. 00:35:11.940 --> 00:35:14.240 We are so spoiled with the tools we have these days. 00:35:14.300 --> 00:35:16.980 And I remember pre-internet, it was hard programming. 00:35:16.980 --> 00:35:18.880 So pre-web anyway. 00:35:18.880 --> 00:35:22.320 So linters, tools that automatically fix things. 00:35:22.320 --> 00:35:23.220 That's what's next. 00:35:23.220 --> 00:35:24.040 Tell us about this. 00:35:24.040 --> 00:35:24.140 Yeah. 00:35:24.140 --> 00:35:27.120 This is really a no brainer in the times we live. 00:35:27.120 --> 00:35:31.300 And actually, yeah, we're spoiled because there was a time I was just manually fixing 00:35:31.300 --> 00:35:35.500 stuff like 8 was giving back till the Blackout of 4 Murder came along. 00:35:35.500 --> 00:35:36.300 Bob, it was worse. 00:35:36.300 --> 00:35:39.600 There was a time where we would argue about how it should be fixed. 00:35:39.760 --> 00:35:41.540 And we, this would be like a conversation. 00:35:41.540 --> 00:35:42.880 And we'd be like, no, no, no. 00:35:42.880 --> 00:35:45.000 We put the commas here and we space it like this. 00:35:45.000 --> 00:35:47.500 It's like, is this really how we should spend our day? 00:35:48.040 --> 00:35:51.960 And it was time for somebody to step in and give them defaults. 00:35:51.960 --> 00:35:53.220 Because I asked the questions. 00:35:53.220 --> 00:35:54.120 And enter Lukas. 00:35:54.120 --> 00:35:54.520 Yeah. 00:35:54.520 --> 00:35:57.320 I asked the question on Twitter the other day, like single or double quotes. 00:35:57.320 --> 00:35:59.000 And there were like 50 commands. 00:35:59.300 --> 00:36:03.220 And there's really, yeah, people are really torn about the default style should be. 00:36:03.220 --> 00:36:08.960 But yeah, Flake 8 to be compliant with Pep 8, which every Python developer should be. 00:36:08.960 --> 00:36:10.280 Black for auto-formatting. 00:36:10.280 --> 00:36:12.780 mypy to the type checks, right? 00:36:12.780 --> 00:36:15.760 As we said before, Python doesn't enforce it. 00:36:15.760 --> 00:36:16.860 So you need a tool for that. 00:36:16.860 --> 00:36:17.940 mypy, hence. 00:36:17.940 --> 00:36:18.460 Yeah. 00:36:18.460 --> 00:36:23.460 And then there's also, Flake 8, for example, has a lot of plugins we might go into next. 00:36:23.580 --> 00:36:27.120 But first I want to highlight, like, you want to automate as much as possible. 00:36:27.120 --> 00:36:29.400 And a pre-commit tool is just awesome. 00:36:29.400 --> 00:36:31.240 It's called pre-commit, right? 00:36:31.240 --> 00:36:34.180 So it's a tool that runs before you try to make a commit. 00:36:34.180 --> 00:36:40.680 So it's a great enforcer locally to not commit any code that's not formatted or that has style 00:36:40.680 --> 00:36:41.900 violations in it. 00:36:41.900 --> 00:36:43.060 Very easy to use. 00:36:43.060 --> 00:36:44.080 Very easy to set up. 00:36:44.080 --> 00:36:46.480 It might take a little bit of work fixing. 00:36:46.480 --> 00:36:50.960 I mean, black auto-formatting is automatic, but maybe you need to fix some Flake errors. 00:36:51.300 --> 00:36:56.620 But I see that as a little bit of work or a little price to pay with every commit to 00:36:56.620 --> 00:36:59.100 avoid a lot of technical debt over time. 00:36:59.100 --> 00:37:03.460 One of the challenges I see for a lot of these things, and linters and testing, they're both 00:37:03.460 --> 00:37:08.740 in this category, is different people on the team who are all working on the same code base 00:37:08.740 --> 00:37:16.280 have very different levels of commitment to, say, writing or running unit tests or formatting 00:37:16.280 --> 00:37:20.460 your code so that it all looks nice and clean before they check it in, right? 00:37:20.600 --> 00:37:23.820 I mean, I've had experiences where like, oh, the build is broken again. 00:37:23.820 --> 00:37:25.180 It's like, well, why is the build broken again? 00:37:25.180 --> 00:37:26.760 Well, someone checked it in. 00:37:26.760 --> 00:37:27.740 Why didn't they notice? 00:37:27.740 --> 00:37:29.120 Well, because they don't run any of the tools. 00:37:29.120 --> 00:37:30.460 Why do they run the tools? 00:37:30.460 --> 00:37:31.640 Because they don't really want to run the tools. 00:37:31.640 --> 00:37:32.520 Like, okay. 00:37:32.520 --> 00:37:35.040 But we're all in this together. 00:37:35.040 --> 00:37:36.340 Let's see what... 00:37:36.340 --> 00:37:40.440 And tools like the pre-commit stuff just mean it's just automatic, right? 00:37:40.440 --> 00:37:43.700 There's not a person to be blamed for saying, well, why didn't you run it? 00:37:43.760 --> 00:37:45.860 Or that person makes me run this tool? 00:37:45.860 --> 00:37:48.440 Or, you know, like there's none of that weird friction. 00:37:48.440 --> 00:37:52.140 It's just like the software said, this is what we agreed on and it's not ready. 00:37:52.140 --> 00:37:56.840 You've got to go, you know, format this line or it'll often just do that itself, right? 00:37:56.840 --> 00:37:57.240 Yep. 00:37:57.240 --> 00:37:58.140 What's the saying? 00:37:58.140 --> 00:38:00.280 If it's not automated, it is broken. 00:38:02.040 --> 00:38:02.760 Yeah, that's a good saying. 00:38:02.760 --> 00:38:05.700 This is as simple as putting the YAML in place. 00:38:05.700 --> 00:38:07.200 I mean, that's a one-time thing. 00:38:07.200 --> 00:38:09.180 Then that's committed to a version control. 00:38:09.180 --> 00:38:11.800 So your collaborator teammate pulls that in. 00:38:11.800 --> 00:38:13.760 You do a pre-commit install. 00:38:13.760 --> 00:38:17.360 It installs the hook locally in your .git folder and you get to go. 00:38:17.360 --> 00:38:19.260 Now all this stuff is enforced. 00:38:19.260 --> 00:38:21.060 You can also do that with GitHub actions. 00:38:21.060 --> 00:38:25.320 But I think the more you do locally at the individual developer level, the better. 00:38:25.320 --> 00:38:26.280 You do both. 00:38:26.280 --> 00:38:26.920 Oh, yeah. 00:38:26.920 --> 00:38:31.840 So ideally, none of the malformed code gets checked in. 00:38:31.920 --> 00:38:32.580 And then fixed. 00:38:32.580 --> 00:38:35.280 And then it shows up as a git diff and, you know, things like that. 00:38:35.280 --> 00:38:39.140 So you could have it on the server just as a safety net. 00:38:39.140 --> 00:38:40.680 Who knows how that got checked in? 00:38:40.680 --> 00:38:43.000 But also have it as a pre-commit hook for most cases. 00:38:43.000 --> 00:38:43.740 Yeah, exactly. 00:38:43.740 --> 00:38:44.220 All right. 00:38:44.220 --> 00:38:45.540 Let's see. 00:38:45.540 --> 00:38:46.460 Next up. 00:38:46.460 --> 00:38:48.960 Narrow exception blocks. 00:38:48.960 --> 00:38:53.320 Yeah, this is something I see quite a lot when I'm reviewing code. 00:38:53.320 --> 00:38:56.100 It's these long blocks between the try and accept. 00:38:56.100 --> 00:38:57.760 So 20, 30 lines. 00:38:57.760 --> 00:39:00.960 And my code review command is always the same. 00:39:01.240 --> 00:39:04.100 Are all these lines of code susceptible to this exception? 00:39:04.100 --> 00:39:06.280 And of course, often they're not. 00:39:06.280 --> 00:39:06.720 Right? 00:39:06.960 --> 00:39:14.060 So narrow your exception blocks, meaning put only code in the try accept that can actually raise that exception. 00:39:14.060 --> 00:39:14.900 And yeah. 00:39:14.900 --> 00:39:15.840 I think it's good advice. 00:39:15.840 --> 00:39:19.900 I think it doesn't have to be just one try accept block either for one huge function. 00:39:19.900 --> 00:39:22.400 You know, you could have try accept do some stuff. 00:39:22.400 --> 00:39:24.760 Try something else if you really need to. 00:39:24.760 --> 00:39:27.220 You know, you can't disambiguate them by exception type. 00:39:27.560 --> 00:39:35.220 But also worth pointing out, I suppose, is the accept star stuff, which is not going to be maybe Python. 00:39:35.220 --> 00:39:35.940 Oh, that's new. 00:39:35.940 --> 00:39:36.180 Yeah. 00:39:36.180 --> 00:39:37.040 Yeah, that's new. 00:39:37.040 --> 00:39:40.440 And I don't know how to search for it because it seems like the star. 00:39:41.340 --> 00:39:42.020 Well, whatever. 00:39:42.020 --> 00:39:42.960 I could just describe. 00:39:42.960 --> 00:39:45.580 But it's really interesting because you can catch multiple exceptions. 00:39:45.580 --> 00:39:48.560 And maybe this actually changes the advice a tiny bit. 00:39:48.560 --> 00:39:51.960 You can catch multiple exceptions for something going wrong. 00:39:51.960 --> 00:39:55.720 So if you were doing it primarily around async, but not just. 00:39:55.980 --> 00:39:59.140 You could say, I'm going to try to talk to the database and this API. 00:39:59.140 --> 00:40:03.120 And if they both break, you know, the accept star will let you catch both. 00:40:03.120 --> 00:40:05.520 Add two separate executions. 00:40:05.520 --> 00:40:08.400 The database exception and the API exception potentially. 00:40:08.400 --> 00:40:08.880 Right. 00:40:08.880 --> 00:40:09.180 Right. 00:40:09.180 --> 00:40:09.880 Interesting. 00:40:09.880 --> 00:40:10.440 Yeah. 00:40:10.440 --> 00:40:11.500 I think that's new. 00:40:11.500 --> 00:40:12.840 Brand new in 3.11. 00:40:12.840 --> 00:40:13.200 Yeah. 00:40:13.200 --> 00:40:14.080 That's a 3.11 thing. 00:40:14.080 --> 00:40:16.940 So it'll be a while till we see that really coming along. 00:40:16.940 --> 00:40:20.940 But, you know, one of the places that might be relevant is there's cool libraries like Tenacity, 00:40:20.940 --> 00:40:23.120 which say, I want to call this function. 00:40:23.120 --> 00:40:24.920 And if it fails, just wait and call it again. 00:40:25.180 --> 00:40:29.480 And then try again and, you know, maybe back off until too much time has passed or give 00:40:29.480 --> 00:40:30.560 it a certain number of attempts. 00:40:30.560 --> 00:40:35.160 But if it failed, but it failed differently three times, you might want to know, well, what 00:40:35.160 --> 00:40:36.460 are all the ways in which it failed? 00:40:36.460 --> 00:40:38.040 Not just the last or the first. 00:40:38.040 --> 00:40:38.600 Right. 00:40:38.600 --> 00:40:42.580 And with the accept star, you could actually catch all of those errors, say, from like a 00:40:42.580 --> 00:40:43.780 retry block or something. 00:40:43.780 --> 00:40:44.260 So. 00:40:44.260 --> 00:40:44.580 Yeah. 00:40:44.580 --> 00:40:45.220 Interesting. 00:40:45.220 --> 00:40:45.540 I don't know. 00:40:45.540 --> 00:40:49.080 It doesn't make this cleaner or simpler to go with. 00:40:49.080 --> 00:40:50.200 It only complicates it. 00:40:50.200 --> 00:40:54.100 But still the idea of like smaller code blocks, I think good advice there. 00:40:54.320 --> 00:40:54.380 Yeah. 00:40:54.380 --> 00:40:55.580 And always name your exceptions. 00:40:55.580 --> 00:40:55.920 Right. 00:40:55.920 --> 00:40:58.060 So sometimes I see try except colon. 00:40:58.060 --> 00:41:00.360 And then we're like, what's exception? 00:41:00.360 --> 00:41:03.000 Because that will just catch anything. 00:41:03.000 --> 00:41:03.400 Right. 00:41:03.400 --> 00:41:05.500 So always be explicit in the exception. 00:41:05.500 --> 00:41:07.180 I just think you understand how this works. 00:41:07.180 --> 00:41:10.700 When you put that in there, there's no more errors in the code. 00:41:10.700 --> 00:41:11.780 It just keeps running. 00:41:11.780 --> 00:41:12.840 It used to crash. 00:41:12.840 --> 00:41:17.320 And if I put except colon and just keep going, way more reliable. 00:41:17.320 --> 00:41:17.860 Yeah. 00:41:17.860 --> 00:41:21.040 What's the saying in the center of Python? 00:41:21.040 --> 00:41:22.680 Errors should not pass silently. 00:41:22.680 --> 00:41:23.560 Yes. 00:41:23.560 --> 00:41:24.040 Exactly. 00:41:24.040 --> 00:41:24.560 I remember. 00:41:24.560 --> 00:41:25.380 Yeah. 00:41:25.460 --> 00:41:25.820 Yeah. 00:41:25.820 --> 00:41:27.200 I've seen some of this code. 00:41:27.200 --> 00:41:28.860 And it's not always bad. 00:41:28.860 --> 00:41:29.960 But it's usually. 00:41:29.960 --> 00:41:31.400 It's usually not good. 00:41:31.400 --> 00:41:31.760 So. 00:41:31.760 --> 00:41:32.120 Yeah. 00:41:32.120 --> 00:41:32.380 Yeah. 00:41:32.380 --> 00:41:34.780 Catch the exceptions by specific type. 00:41:34.780 --> 00:41:36.940 Handle different ones potentially differently. 00:41:36.940 --> 00:41:37.440 And so on. 00:41:37.440 --> 00:41:37.880 Yeah. 00:41:37.880 --> 00:41:41.200 And maybe that kind of leads us into number six here more broadly. 00:41:41.200 --> 00:41:44.440 That's one of the Pythonic or idiomatic things of Python. 00:41:44.440 --> 00:41:44.760 Right. 00:41:44.760 --> 00:41:45.780 But there's a whole bunch more. 00:41:45.780 --> 00:41:46.800 And that's your next tip. 00:41:46.800 --> 00:41:47.140 Yeah. 00:41:47.140 --> 00:41:53.220 This can, of course, be a whole series of articles because there's so much what can be considered idiomatic or not. 00:41:53.220 --> 00:42:00.800 But yeah, there's sometimes you see people reinventing the wheel and they can perfectly well use the standard library. 00:42:00.800 --> 00:42:03.740 There's also a very rich set of built-ins. 00:42:03.740 --> 00:42:04.060 Right. 00:42:04.060 --> 00:42:06.100 Like all any those built-ins. 00:42:06.240 --> 00:42:16.700 But then also style-wise, there's this concept of leaping, checking before you leap versus just do something and ask for forgiveness rather than permission. 00:42:16.700 --> 00:42:21.460 So, for example, code that overly checks if a file exists or can be opened. 00:42:21.460 --> 00:42:22.460 So all these conditionals. 00:42:22.460 --> 00:42:29.500 What's often considered more Pythonic is to just try open a file, try to do something and then catch the exception. 00:42:29.500 --> 00:42:30.040 Right. 00:42:30.040 --> 00:42:31.120 So that's why it's called. 00:42:31.120 --> 00:42:31.460 Right. 00:42:31.460 --> 00:42:34.700 It's easier to ask for forgiveness than permission. 00:42:34.700 --> 00:42:35.180 Yeah. 00:42:35.300 --> 00:42:36.300 Yes, exactly. 00:42:36.300 --> 00:42:44.480 As opposed to like a C language or something where you do six or seven checks to make sure everything is set up just right. 00:42:44.480 --> 00:42:52.420 And then, you know, I'm going to check that the file is not just that it's not null and that it has a null terminating character. 00:42:52.420 --> 00:42:56.000 And now I'm going to check that I have access to the files. 00:42:56.000 --> 00:43:00.280 You know, you're like there's if you write, if you go and read a lot of C code, there's like check, check, check, check, check, check, check. 00:43:00.640 --> 00:43:01.340 Do the thing. 00:43:01.700 --> 00:43:07.500 And usually that's because there's a page fault and the program just goes, whoof, and just goes away if you touch it wrong. 00:43:07.500 --> 00:43:13.860 Whereas Python almost always, not always, but almost always the result is here's an exception you can catch and handle. 00:43:13.860 --> 00:43:17.100 And it tells you what went wrong instead of trying to think of all the checks. 00:43:17.120 --> 00:43:18.540 Because there's probably a check you forgot. 00:43:18.540 --> 00:43:20.040 Just give it a shot. 00:43:20.040 --> 00:43:20.360 Right? 00:43:20.360 --> 00:43:20.680 Right. 00:43:20.680 --> 00:43:23.940 And it's also, it's kind of the positive mindset. 00:43:23.940 --> 00:43:25.120 Like usually it works. 00:43:25.120 --> 00:43:27.060 And if it doesn't work, we deal with the consequences. 00:43:27.600 --> 00:43:31.820 Whereas if you do all these if checks, that's code that always runs and might not be necessary. 00:43:31.820 --> 00:43:33.260 So it might even be faster. 00:43:33.260 --> 00:43:33.660 Right? 00:43:33.660 --> 00:43:34.060 For sure. 00:43:34.060 --> 00:43:43.320 So more of the ideas that came to mind when I was reading your idiomatic code section was just one use that you did mention this a little bit, but I'll reinforce it is you said use a standard library. 00:43:43.320 --> 00:43:51.120 And one of the things I learned from working with you is there, you know, sort of, I would try to pull another, other library, other things from IPI or something. 00:43:51.120 --> 00:43:52.340 You're like, look, this is built in. 00:43:52.340 --> 00:43:53.520 Why don't you just use, you know what? 00:43:53.520 --> 00:43:54.180 You're right. 00:43:54.180 --> 00:43:55.120 That's built in. 00:43:55.120 --> 00:43:56.040 That seems pretty handy. 00:43:56.040 --> 00:43:56.260 Right? 00:43:56.300 --> 00:43:59.880 Like, for example, counter is definitely one that I use all the time because of you. 00:43:59.880 --> 00:44:00.580 And a collection. 00:44:00.580 --> 00:44:02.360 Yeah, exactly. 00:44:02.360 --> 00:44:10.620 So embracing what's there instead of maybe getting another library or just trying to write that algorithm yourself because who knew it existed? 00:44:10.620 --> 00:44:12.600 Didn't study the standard library enough. 00:44:12.600 --> 00:44:14.780 I just came from C and this is how we do it in C. 00:44:14.780 --> 00:44:15.900 So I'm going to try to do that here. 00:44:15.900 --> 00:44:16.080 Right? 00:44:16.080 --> 00:44:19.740 Like the idiomatic steps that you can take are really good there. 00:44:19.740 --> 00:44:24.560 But also lambdas versus regular functions for like little inline things. 00:44:24.740 --> 00:44:29.260 You mentioned some of the ones that take generators for like all and any and these other tests. 00:44:29.260 --> 00:44:31.780 And there's just a lot of cool little language features. 00:44:31.780 --> 00:44:32.180 Yeah. 00:44:32.180 --> 00:44:32.620 Decorators. 00:44:32.620 --> 00:44:33.120 I've got to use later. 00:44:33.120 --> 00:44:34.220 Yeah. 00:44:34.220 --> 00:44:34.460 Yeah. 00:44:34.460 --> 00:44:34.860 Decorators. 00:44:34.860 --> 00:44:35.200 Definitely. 00:44:35.200 --> 00:44:37.000 I would put it in that space as well. 00:44:37.000 --> 00:44:38.180 And the wit statement. 00:44:38.180 --> 00:44:41.400 Context managers to automatically clean up resources. 00:44:41.400 --> 00:44:42.700 Pretty important feature. 00:44:42.700 --> 00:44:43.280 Mm-hmm. 00:44:43.280 --> 00:44:44.080 Mm-hmm. 00:44:44.460 --> 00:44:46.920 Another one that is near and dear to my heart. 00:44:46.920 --> 00:44:48.540 You're number seven on this list. 00:44:48.540 --> 00:44:56.060 Near to dear because I have suffered badly the consequences of choosing wrongly is choose the right data structures. 00:44:56.060 --> 00:44:56.820 Tell us about that. 00:44:56.820 --> 00:44:57.160 Yeah. 00:44:57.260 --> 00:44:59.440 This is very important for performance. 00:44:59.440 --> 00:44:59.740 Right? 00:44:59.740 --> 00:45:02.800 So where you kind of need to understand just the fundamentals here. 00:45:02.800 --> 00:45:03.040 Right? 00:45:03.040 --> 00:45:06.700 Like list versus sets and dictionaries and how they perform. 00:45:06.700 --> 00:45:13.140 For example, if you're very big collection of a million items and you would leave that as a list, yet you want to do searches or lookups. 00:45:13.300 --> 00:45:16.140 Then how this works is they traverse them item by item. 00:45:16.140 --> 00:45:16.400 Right? 00:45:16.400 --> 00:45:22.280 Where if you would make that a set, it's now in big O notation, O1, because there's hashing going on. 00:45:22.280 --> 00:45:26.100 So it can immediately find the value because they're hashed. 00:45:26.100 --> 00:45:26.300 Right? 00:45:26.300 --> 00:45:34.000 So that's a small, well, a pretty fundamental example because we work with lists and sets and dictionaries all the time. 00:45:34.000 --> 00:45:36.380 But those are very important to know. 00:45:36.380 --> 00:45:37.380 They are. 00:45:37.380 --> 00:45:40.920 The dictionary and the set one can't emphasize that enough. 00:45:40.920 --> 00:45:43.000 I mean, obviously, we use dictionaries so much. 00:45:43.340 --> 00:45:51.560 But if you've got a list, but you think you might need to look up stuff in that list based on, say, if it's a list of objects, some field of that object. 00:45:51.560 --> 00:45:56.180 If you would make that a dictionary, make the key of the field, then it's not a little bit faster. 00:45:56.180 --> 00:45:58.520 It's unbelievably faster. 00:45:58.520 --> 00:46:01.380 My mind just never ceases to be amazed. 00:46:01.380 --> 00:46:02.020 Like, you know what? 00:46:02.020 --> 00:46:05.600 It really, it went through a million items that fast, like instantly. 00:46:05.600 --> 00:46:06.360 Right? 00:46:06.360 --> 00:46:07.880 It's so different. 00:46:07.880 --> 00:46:12.520 Or if you see people writing code, here's some more of the idiomatic stuff is I'm looping over a thing. 00:46:12.520 --> 00:46:14.400 I want to build up this list of them. 00:46:14.400 --> 00:46:15.540 But I want duplicates. 00:46:15.540 --> 00:46:20.020 You might see if this thing is not, you know, look in the list for it, then you can add it. 00:46:20.020 --> 00:46:21.220 Like, just don't do that. 00:46:21.220 --> 00:46:22.980 Just make a set and just jam it in there. 00:46:22.980 --> 00:46:24.860 And it'll reject the duplicates. 00:46:24.860 --> 00:46:25.080 Right? 00:46:25.080 --> 00:46:28.400 Like, there's a lot of things where this ties back to your idiomatic one as well. 00:46:28.400 --> 00:46:28.800 Yeah. 00:46:28.800 --> 00:46:30.680 Another one I highlight there are decks. 00:46:30.680 --> 00:46:31.260 Right? 00:46:31.360 --> 00:46:39.200 So when you do inserts and leads on both ends of a sequence, that's also generally slow with a list for the same reason. 00:46:39.200 --> 00:46:43.980 Because as the search example is that it needs to remap values, right? 00:46:43.980 --> 00:46:44.760 Massively. 00:46:44.760 --> 00:46:48.420 And a deck is designed to do that fast on both ends. 00:46:48.420 --> 00:46:57.640 So anytime I need to, if it's a big collection and I need to insert stuff on at the start, then a collection, a deck from the collections module is a better choice. 00:46:57.760 --> 00:46:58.440 Yeah, absolutely. 00:46:58.440 --> 00:47:02.740 Another thing, I guess, giving a little quick shout out here is the default dict is really nice, too. 00:47:02.740 --> 00:47:03.120 Oh, yeah. 00:47:03.120 --> 00:47:07.160 For removing tests and checks and initialize. 00:47:07.160 --> 00:47:09.680 Because you don't have to check if a key is in the dictionary. 00:47:09.680 --> 00:47:11.520 You can just assume it's there. 00:47:11.520 --> 00:47:13.200 And, yeah, that leads. 00:47:13.200 --> 00:47:15.640 You can ditch a whole bunch of if statements. 00:47:15.640 --> 00:47:17.320 Yep, exactly. 00:47:17.320 --> 00:47:19.380 It's the job of the dictionary, not your job now. 00:47:19.380 --> 00:47:20.280 Yeah, nice. 00:47:20.280 --> 00:47:20.640 All right. 00:47:20.640 --> 00:47:21.320 Let me see. 00:47:21.320 --> 00:47:23.180 Do I have any others that I want to squeeze in here? 00:47:23.180 --> 00:47:32.100 Okay, so here's one that I wanted to sneak in before we get further beyond this is to use guarding clauses. 00:47:32.100 --> 00:47:37.680 And so often what I'll see, especially when people are new, is writing code that looks like this. 00:47:37.680 --> 00:47:42.120 It's like, it looks to me like a saw, a lumberjack would use or something. 00:47:42.120 --> 00:47:45.860 It's just like zip, zip, zip, out, and then back, and then out, and then back. 00:47:45.860 --> 00:47:46.780 And you're like, whoa. 00:47:46.780 --> 00:47:52.120 You know, it's usually like it starts in the middle of the editor window and it goes to the right. 00:47:52.120 --> 00:47:53.280 You're like, what is this? 00:47:53.280 --> 00:48:00.340 And, you know, it's usually if some case and then if some other case, maybe do a little step, then if another case. 00:48:00.340 --> 00:48:07.500 And it's like assuming that it's got to build up a bunch of these steps before it can sort of go down the happy path. 00:48:07.500 --> 00:48:11.140 So it's going to check everything that could possibly go wrong before it tries to do that. 00:48:11.140 --> 00:48:13.580 And I don't know how you feel about guarding clauses. 00:48:13.580 --> 00:48:14.920 I love guarding clauses. 00:48:14.920 --> 00:48:15.840 Yeah, you do? 00:48:15.840 --> 00:48:17.920 So tell people about this sort of alternative. 00:48:17.920 --> 00:48:20.420 It's so simple, but it makes such a difference. 00:48:20.420 --> 00:48:22.800 Yeah, it goes back to the Xenophython again. 00:48:22.800 --> 00:48:24.260 Flat is better than nested. 00:48:24.260 --> 00:48:29.320 So nested, deeply nested code is just inherently, it's more complex. 00:48:29.320 --> 00:48:30.080 Painful. 00:48:30.080 --> 00:48:32.440 And it's harder to maintain. 00:48:32.440 --> 00:48:35.420 Yeah, it's called the arrow, arrow shape. 00:48:35.420 --> 00:48:39.020 I learned from this article that it's also called the staircase, which is nice. 00:48:39.020 --> 00:48:42.960 But yeah, you can, if you look up our arrow shape, it explains more about it. 00:48:42.960 --> 00:48:48.000 But yeah, it's just more complex because, yeah, it's again, that cyclomatic complexity, right? 00:48:48.000 --> 00:48:50.740 The amount of paths you have through your code. 00:48:50.740 --> 00:48:56.580 And if you, in this case, reverse all these statements and early return, the code is now way flatter. 00:48:56.580 --> 00:48:59.740 It's easier to read and less complex, right? 00:48:59.820 --> 00:49:02.460 So this code looks really reasonable. 00:49:02.460 --> 00:49:05.500 And yeah, the other is just very hard to follow. 00:49:05.500 --> 00:49:07.060 You don't even know. 00:49:07.060 --> 00:49:11.280 And there's all these weird interplays of like, well, what if this is true, but that's false? 00:49:11.280 --> 00:49:13.120 And could you actually get into that if case? 00:49:13.120 --> 00:49:18.020 Whereas these guarding clauses just say, if this is wrong, bail out of this function. 00:49:18.020 --> 00:49:20.180 If this other case is wrong, bail out. 00:49:20.300 --> 00:49:22.820 Just like return false or don't do the thing or whatever. 00:49:22.820 --> 00:49:28.740 And then eventually, once you've hit all those with very little indentation, then you have the thing you wanted to get to. 00:49:28.740 --> 00:49:32.180 And it also kind of makes them a little bit unrelated to each other. 00:49:32.180 --> 00:49:32.500 Yeah. 00:49:32.500 --> 00:49:34.400 Unlike the super nested style. 00:49:34.400 --> 00:49:36.940 Yeah, I guess, yeah, the cyclomatic complexity, right? 00:49:36.940 --> 00:49:40.020 The amount of combinations you can have with this is less. 00:49:40.020 --> 00:49:41.400 Hence, it's less complex. 00:49:41.400 --> 00:49:43.540 Hence, it's easier to maintain. 00:49:43.540 --> 00:49:46.040 And readability here is way better. 00:49:46.040 --> 00:49:47.160 Yeah, I totally agree. 00:49:47.600 --> 00:49:53.780 So when you see things like flat is better than nested in the Xen of Python, you're like, cool, but I got to test some stuff. 00:49:53.780 --> 00:49:55.380 So it's getting nested, right? 00:49:55.380 --> 00:50:03.480 Like it's, I just, there's nothing in that statement that it tells you, well, what are the mechanics that you consider to avoid that, right? 00:50:03.480 --> 00:50:04.600 It's just, well, it's complicated. 00:50:04.600 --> 00:50:05.060 I'm sorry. 00:50:05.060 --> 00:50:06.120 It's going to be nested, right? 00:50:06.120 --> 00:50:07.700 It would be better if it weren't, but it is. 00:50:07.700 --> 00:50:08.800 Well, not actually. 00:50:08.800 --> 00:50:13.540 Like guarding clauses almost always will lessen it, if not really, really decrease it. 00:50:13.540 --> 00:50:14.780 Yeah, that's a good point. 00:50:14.780 --> 00:50:18.180 Like the Xen tells you the what, but not necessarily the how. 00:50:18.180 --> 00:50:21.460 And the guard clause is that this is a particular technique. 00:50:21.460 --> 00:50:24.560 Another one in refactoring is the extract method refactoring. 00:50:24.560 --> 00:50:30.420 And that's where we pull out a bunch of code into a new function, which also often leads to less nested code. 00:50:30.420 --> 00:50:30.920 Indeed. 00:50:30.920 --> 00:50:32.040 Is that your next one? 00:50:32.040 --> 00:50:32.560 Refactoring? 00:50:32.560 --> 00:50:33.000 Could be. 00:50:33.000 --> 00:50:34.680 I think that was a bonus. 00:50:34.680 --> 00:50:35.200 I skipped over a bunch. 00:50:35.200 --> 00:50:36.380 That's right. 00:50:36.380 --> 00:50:38.020 It was a bonus here at the end. 00:50:38.020 --> 00:50:38.540 Absolutely. 00:50:39.000 --> 00:50:44.240 So that's where you gave a shout out to the refactoring book, which also had those code smells in them. 00:50:44.240 --> 00:50:44.560 Totally. 00:50:44.560 --> 00:50:45.020 Yeah. 00:50:45.020 --> 00:50:46.440 Do you still recommend people read that? 00:50:46.440 --> 00:50:51.240 I mean, I read it with bated breath in 1999 or whenever that thing came out. 00:50:51.240 --> 00:50:53.080 It was really an important book. 00:50:53.080 --> 00:50:54.460 And I'm like, this has changed everything. 00:50:54.460 --> 00:50:58.960 But, you know, that's 2025 years ago, something like that when it actually came out. 00:50:59.060 --> 00:50:59.940 Yeah, that's a good point. 00:50:59.940 --> 00:51:02.020 I think the tooling has improved. 00:51:02.020 --> 00:51:04.920 But still, I think conceptually, this is still an important book. 00:51:04.920 --> 00:51:06.680 I was reading parts of it again. 00:51:06.680 --> 00:51:13.660 Honestly, I do like the first edition a bit better sometimes because it uses Java, where this uses JavaScript. 00:51:13.660 --> 00:51:16.200 And I don't know, the paper quality. 00:51:16.200 --> 00:51:21.780 I'm not a fan of Java, but I think I might actually prefer the Java or the JavaScript, to be honest. 00:51:22.080 --> 00:51:23.780 But it's very fundamental stuff. 00:51:23.780 --> 00:51:30.700 And, yeah, it still has, it's also nice that it's a catalog, so you don't have to read it end to end. 00:51:30.700 --> 00:51:34.480 You can just zoom into parts that are relevant for you at that moment. 00:51:34.480 --> 00:51:36.280 So, the collection of things. 00:51:36.280 --> 00:51:36.640 Okay. 00:51:36.640 --> 00:51:37.600 Very interesting. 00:51:37.600 --> 00:51:42.160 So, I guess another one, I don't remember if it was directly in your article. 00:51:42.160 --> 00:51:43.900 I don't think so. 00:51:43.900 --> 00:51:48.100 It was just sort of implied throughout, was, you know, embrace refactoring. 00:51:48.220 --> 00:51:56.900 You opened the, alluding to this at the beginning of this conversation, is I see a lot of people who get stuck thinking about, I've got to get this right. 00:51:56.900 --> 00:51:59.180 I know if I start wrong, I'm going to hate it. 00:51:59.180 --> 00:52:00.460 It's going to be hard to work on. 00:52:00.460 --> 00:52:01.840 It's going to be so bad. 00:52:01.840 --> 00:52:06.980 So, I've got to sit here and think for, like, two weeks to get started on this project so I get it right. 00:52:06.980 --> 00:52:08.480 You know what you could also do? 00:52:08.480 --> 00:52:10.900 Just pick one way that seems right at the time. 00:52:10.900 --> 00:52:12.020 Spend a week on it. 00:52:12.020 --> 00:52:14.500 If it's not working, it'll refactor to the other. 00:52:14.500 --> 00:52:17.340 Or even throw it away and go to the other option, right? 00:52:17.380 --> 00:52:19.100 Like, there's a lot of people kind of stuck. 00:52:19.100 --> 00:52:31.660 And I think embracing the idea of refactoring, maybe not in the traditional by-hand effect of Martin Fowler's original book, but, you know, we have tools that do a lot of this automatically or almost automatically, you know, right-click and ask it to. 00:52:31.660 --> 00:52:33.720 So, what are your thoughts? 00:52:33.720 --> 00:52:39.840 I definitely think people should at least catch the zen of it, if not go through the book, because the tools will take care of it. 00:52:39.840 --> 00:52:42.420 Yeah, you still want to know the concepts here. 00:52:42.420 --> 00:52:49.560 The different techniques, as I already highlighted, the extract method, for example, grouping constants into enums we've mentioned before. 00:52:49.560 --> 00:52:54.720 So, a lot of actually what we've spoken about so far can be found in this book as well, right? 00:52:54.780 --> 00:53:01.340 And I think overall, the goal of refactoring is to keep that technical depth in check, right? 00:53:01.340 --> 00:53:04.400 So, avoid, suffer a rut, they also say. 00:53:04.400 --> 00:53:14.440 And, yeah, as you start to add more code and cover more scenarios and the always changing requirements, inevitably, what happens? 00:53:14.560 --> 00:53:16.180 You kind of need to learn. 00:53:16.180 --> 00:53:21.420 You thought it was one thing, but as you got further into it, you're like, you know, that part's actually, that's where the problem is. 00:53:21.420 --> 00:53:24.060 I didn't think so, but now I know, because that's where it's hard, right? 00:53:24.060 --> 00:53:26.160 Which you only learn as you go, right? 00:53:26.160 --> 00:53:27.400 Yeah, that's a good point. 00:53:27.400 --> 00:53:34.540 Right, but the people who are stuck, I don't think they internalize that, like, the only way to know where you're going to get stuck further down the road is to go down the road. 00:53:34.540 --> 00:53:36.860 You can't think about it very well. 00:53:36.860 --> 00:53:41.600 There are a couple of interesting comments here with respect to garden clauses. 00:53:41.780 --> 00:53:51.460 Alvaro says, you could go and put assert statements at the beginning of functions to indicate some of the assumptions that could be disabled in production and give nice errors on pytest. 00:53:51.460 --> 00:53:52.880 So, pytest, rather. 00:53:52.880 --> 00:53:54.040 Yeah, possible. 00:53:54.040 --> 00:53:55.000 What do you think, Bob? 00:53:55.000 --> 00:54:01.960 Yeah, asserts are great, but, yeah, I'm happy that you highlight the caveat that they can be disabled, so you cannot always rely on them. 00:54:01.960 --> 00:54:04.540 I definitely see a place for asserts. 00:54:04.540 --> 00:54:10.340 And, of course, you use them in pytest all the time to assert different ways your function performs. 00:54:10.820 --> 00:54:13.140 I use most of my asserts in pytest, yeah. 00:54:13.140 --> 00:54:18.880 But I can definitely see a place for this scenario that Alvaro highlights. 00:54:18.880 --> 00:54:28.500 Yeah, and then Brandon Outlawdience has a very realistic problem that people run into is, I work a lot of places where they don't give you the time to do the refactoring and make things better. 00:54:28.500 --> 00:54:34.100 And so it just builds up until it becomes not ideal, as his second comment here implies. 00:54:34.100 --> 00:54:34.880 That's a good point. 00:54:34.880 --> 00:54:35.900 That is a real problem. 00:54:35.900 --> 00:54:38.140 And I'll tell you how I solved it. 00:54:38.140 --> 00:54:42.080 Bob, maybe we're getting short on time, but you can tell me real quick how you solved it. 00:54:42.280 --> 00:54:47.860 For me, when my managers and folks would say, Michael, what is your estimate for how long this is going to take? 00:54:47.860 --> 00:54:53.680 If I thought it was going to take five hours, but maybe I would need to do an hour or two of refactoring, this feature took seven hours. 00:54:53.680 --> 00:54:55.760 Like, you want it done, it's going to take seven hours. 00:54:56.040 --> 00:54:59.680 Because if I'm going to do it, I'm going to do it right, because I'm going to have to work on it afterwards. 00:54:59.680 --> 00:55:02.540 And I know it's just going to get worse if I... 00:55:02.540 --> 00:55:10.160 So I wouldn't exactly lie to them, but I would include the time to make it right, not just make it work as part of my estimate. 00:55:10.160 --> 00:55:12.100 Yeah, maybe even double it, right? 00:55:12.100 --> 00:55:22.920 Because there's the initial version, and there's the testing, there's the documentation, there are bug fixes, there are inevitably are requirement changes in the sprint meetings. 00:55:23.940 --> 00:55:30.040 So it might, five hours might just be that initial draft almost, but maybe it should then be 10 hours. 00:55:30.040 --> 00:55:31.040 Yeah, perhaps. 00:55:31.040 --> 00:55:36.420 But whatever it is, clean code should be part of the deliverable, in my opinion. 00:55:36.420 --> 00:55:38.060 And it should be part of the estimate. 00:55:38.060 --> 00:55:41.040 I was saying estimate times three plus two weeks. 00:55:41.040 --> 00:55:42.200 That's a nice one. 00:55:42.200 --> 00:55:43.680 Exactly. 00:55:43.680 --> 00:55:45.080 That is a good one. 00:55:45.080 --> 00:55:45.780 Very good. 00:55:45.780 --> 00:55:46.420 All right. 00:55:46.420 --> 00:55:48.740 Well, we're getting short on time here. 00:55:48.740 --> 00:55:49.680 Let me do something. 00:55:49.680 --> 00:55:53.540 I want to do something that's kind of different, Bob, because I think this is actually... 00:55:53.540 --> 00:55:55.040 Let me share a different thing here. 00:55:55.040 --> 00:56:00.340 I think that this is something people are going to have to start thinking about as well as maybe an option here. 00:56:00.340 --> 00:56:03.580 So what about asking AI assistants? 00:56:03.580 --> 00:56:06.560 Things like Google Copilot or ChatGP. 00:56:06.560 --> 00:56:09.840 There might be some cases where people say, here's my code. 00:56:09.840 --> 00:56:11.200 Hey, thing, could you make it better? 00:56:11.200 --> 00:56:13.300 So for example, let's do this to close out the show. 00:56:13.300 --> 00:56:13.660 Okay, Bob? 00:56:13.660 --> 00:56:14.260 Sure. 00:56:14.340 --> 00:56:17.680 How can we write plain code in Python? 00:56:17.680 --> 00:56:19.280 I'm going to ask ChatGP. 00:56:19.280 --> 00:56:23.280 We have already covered this. 00:56:23.280 --> 00:56:23.880 Are you sharing? 00:56:23.880 --> 00:56:24.140 What else? 00:56:24.140 --> 00:56:24.580 All right. 00:56:24.580 --> 00:56:25.360 Oh, hold on. 00:56:25.360 --> 00:56:26.020 I thought so. 00:56:26.020 --> 00:56:26.500 I did. 00:56:26.500 --> 00:56:27.160 I forgot to add a stream. 00:56:27.160 --> 00:56:29.120 So I'm going to ask ChatGP here. 00:56:29.120 --> 00:56:30.700 And what else does it say? 00:56:30.700 --> 00:56:32.200 So I gave it all of your tips. 00:56:32.200 --> 00:56:33.500 And I said, we already discussed that. 00:56:33.500 --> 00:56:34.280 What else can we do? 00:56:34.280 --> 00:56:35.920 Is it based in the article as well? 00:56:35.920 --> 00:56:36.900 No, I didn't give it the article. 00:56:37.020 --> 00:56:38.940 Just the headings. 00:56:38.940 --> 00:56:40.900 So it says you can document your code. 00:56:40.900 --> 00:56:42.640 Keep it simple, which it didn't understand. 00:56:42.640 --> 00:56:43.660 Follow PEP 8. 00:56:43.660 --> 00:56:45.340 This is an interesting one. 00:56:45.340 --> 00:56:46.900 Exceptions are for error handling. 00:56:46.900 --> 00:56:50.300 So anyway, I just thought it might be kind of fun to think about, you know, 00:56:50.300 --> 00:56:53.340 could we ask these things to help us and improve our code? 00:56:53.340 --> 00:56:56.120 I don't know if you played with any of this, but it could be fun. 00:56:56.120 --> 00:56:56.960 I have not yet. 00:56:56.960 --> 00:56:58.280 That's Julian's department. 00:56:58.280 --> 00:57:00.760 He's geeking out over the tool. 00:57:00.760 --> 00:57:06.720 But I'm high on my list to try it out because it's really mind-blowing. 00:57:06.720 --> 00:57:08.260 What this tool is doing. 00:57:08.260 --> 00:57:08.720 Yeah. 00:57:08.720 --> 00:57:11.520 I had a program that I wrote. 00:57:11.520 --> 00:57:17.040 And let's just see if I can go to, let's grab some random gist here on GitHub. 00:57:17.040 --> 00:57:18.000 Let's see. 00:57:18.000 --> 00:57:23.160 So you can take these things, this random code, and say, you know, things like, 00:57:23.160 --> 00:57:25.040 here's a Python program. 00:57:25.040 --> 00:57:28.300 How can I make it more readable? 00:57:28.300 --> 00:57:33.220 You can give it this long thing and it'll say, you know, look, there were no doc strings. 00:57:33.220 --> 00:57:36.220 There's some places where you had meaningful variables are missing. 00:57:36.220 --> 00:57:36.640 Yeah. 00:57:36.640 --> 00:57:38.460 Could have grouped the imports better. 00:57:38.460 --> 00:57:39.940 Could add more type hints. 00:57:39.940 --> 00:57:41.180 And then it rewrites it. 00:57:41.180 --> 00:57:45.540 So, for example, this is my code to integrate with turnstile. 00:57:45.540 --> 00:57:49.420 And so it's, you know, you see it putting type hints and stuff as it goes. 00:57:49.420 --> 00:57:49.600 Typing there. 00:57:49.600 --> 00:57:49.960 Yeah. 00:57:49.960 --> 00:57:50.480 Yeah. 00:57:50.480 --> 00:57:50.880 Yeah. 00:57:50.880 --> 00:57:51.160 Yeah. 00:57:51.160 --> 00:57:52.500 So anyway, I don't know. 00:57:52.500 --> 00:57:58.500 I feel like this is, as much as looking back 25 years and seeing refactoring go that seminal, 00:57:58.940 --> 00:58:05.540 you know, maybe, maybe, maybe this kind of stuff is going to have to be something that we take into consideration going forward. 00:58:05.540 --> 00:58:05.840 So. 00:58:05.840 --> 00:58:06.240 Yeah. 00:58:06.240 --> 00:58:06.840 Wow. 00:58:06.840 --> 00:58:07.540 Pretty impressive. 00:58:07.540 --> 00:58:08.180 Yeah. 00:58:08.180 --> 00:58:08.280 Yeah. 00:58:08.280 --> 00:58:08.920 We will see. 00:58:08.920 --> 00:58:09.320 We'll see. 00:58:09.320 --> 00:58:12.200 So anyway, that was fun, but let's, let's close it out. 00:58:12.200 --> 00:58:12.700 Yeah. 00:58:12.800 --> 00:58:13.460 Excellent work. 00:58:13.460 --> 00:58:16.280 I mean, I feel like we only just touched the surface, right? 00:58:16.280 --> 00:58:17.580 This could go on and on. 00:58:17.580 --> 00:58:22.020 JF out in the audience asked about unit testing and we barely touched on that. 00:58:22.020 --> 00:58:25.600 There's a bunch of, bunch more areas, but I think we're out of time. 00:58:25.600 --> 00:58:25.880 Yeah. 00:58:25.920 --> 00:58:27.320 The sun is coming up in your world. 00:58:27.320 --> 00:58:27.900 I can see. 00:58:27.900 --> 00:58:31.020 Thousand pager books have been written about this. 00:58:31.020 --> 00:58:32.040 It's, it's a whole field. 00:58:32.040 --> 00:58:33.200 So yeah. 00:58:33.200 --> 00:58:33.460 Yeah. 00:58:33.460 --> 00:58:36.040 We, we mentioned a couple of important things, I think. 00:58:36.040 --> 00:58:36.340 Yeah. 00:58:36.340 --> 00:58:37.000 We sure did. 00:58:37.000 --> 00:58:41.080 Well, it's certainly a lot of things that people can take and they do sound simple. 00:58:41.080 --> 00:58:46.940 Like, well, write smaller programs and give them good names or write smaller parts of your program and give it good names. 00:58:46.940 --> 00:58:49.560 But that it's like a never ending journey to do that right. 00:58:49.560 --> 00:58:51.340 And to keep on it. 00:58:51.340 --> 00:58:51.560 Right. 00:58:51.560 --> 00:58:53.900 So there's a lot of nuance as well. 00:58:53.900 --> 00:58:54.240 Right. 00:58:54.240 --> 00:58:54.700 There is. 00:58:54.700 --> 00:58:55.220 Absolutely. 00:58:55.220 --> 00:58:55.780 All right. 00:58:55.820 --> 00:58:58.840 Well, quick two final questions before you get out of here. 00:58:58.840 --> 00:59:03.480 If you're going to write some clean Python code editor, what do you use these days? 00:59:03.480 --> 00:59:09.500 Well, the coaches, the team almost had me on VS Code, which is an amazing idea. 00:59:09.500 --> 00:59:16.640 But it was not as super fast, of course, but for me, for my workflow, it was not as fast as Vim. 00:59:16.640 --> 00:59:19.340 So I stuck with Vim and I do everything. 00:59:19.340 --> 00:59:20.980 It's just a setup, right? 00:59:20.980 --> 00:59:23.340 With all the plugins and shortcuts. 00:59:23.340 --> 00:59:25.360 And it makes me fast. 00:59:25.720 --> 00:59:26.840 And the muscle memory. 00:59:26.840 --> 00:59:27.280 Yeah. 00:59:27.280 --> 00:59:27.600 Yeah. 00:59:27.600 --> 00:59:36.600 It's one of those things where, you know, you could change to something potentially, but how long are you going to be in a degraded state of working before you gain enough experience? 00:59:36.600 --> 00:59:38.180 And will it actually be that much better? 00:59:38.180 --> 00:59:39.800 You know, there's a lot to it, right? 00:59:39.860 --> 00:59:45.800 And once a tool introduces a mouse and I have the other option of only using a keyboard, then it's still the keyboard. 00:59:45.800 --> 00:59:46.140 Yeah. 00:59:46.140 --> 00:59:46.440 Yeah. 00:59:46.440 --> 00:59:47.140 Yeah, for sure. 00:59:47.140 --> 00:59:47.740 Okay. 00:59:47.740 --> 00:59:50.260 And the notable PyPI package you've come across lately? 00:59:50.480 --> 00:59:50.760 Yeah. 00:59:50.760 --> 00:59:50.880 Yeah. 00:59:50.880 --> 00:59:52.800 This is such a hard question. 00:59:52.800 --> 00:59:55.640 I think I've mentioned requests in the past. 00:59:55.640 --> 01:00:01.720 These days there's HTTPX because we're using a lot of code to consume APIs. 01:00:01.720 --> 01:00:03.580 And now you can do that synchronously. 01:00:03.680 --> 01:00:06.940 But now maybe the shout is really for Sebastian Ramirez. 01:00:06.940 --> 01:00:09.060 SQL model, FastAPI, typer. 01:00:09.060 --> 01:00:13.220 Apart from amazing tools, the documentation, it's so pleasant. 01:00:13.220 --> 01:00:14.420 I keep going back. 01:00:14.420 --> 01:00:16.720 And because I teach those tools as well, right? 01:00:16.720 --> 01:00:17.560 To other developers. 01:00:17.800 --> 01:00:20.060 I can just teach them from the documentation. 01:00:20.060 --> 01:00:23.080 It's really good with solid code samples. 01:00:23.080 --> 01:00:25.620 So FastAPI, I guess it is then. 01:00:25.620 --> 01:00:27.000 Right on. 01:00:27.000 --> 01:00:31.580 And all those things you named there, an important piece in the mix are Python types and Pydantic. 01:00:31.580 --> 01:00:32.740 Yeah, exactly. 01:00:32.740 --> 01:00:33.400 Exactly. 01:00:33.400 --> 01:00:36.860 That really took the type hints to the next level. 01:00:36.860 --> 01:00:37.280 It did. 01:00:37.280 --> 01:00:37.640 Yeah. 01:00:37.640 --> 01:00:38.120 Yeah. 01:00:38.120 --> 01:00:38.740 It definitely did. 01:00:38.740 --> 01:00:39.360 All right. 01:00:39.360 --> 01:00:40.600 Well, final call to action. 01:00:40.600 --> 01:00:42.660 People are interested in this. 01:00:42.660 --> 01:00:46.460 Maybe they're interested in getting to know some of your coaching stuff better as well. 01:00:46.460 --> 01:00:47.300 What do you tell them? 01:00:47.400 --> 01:00:47.520 Yeah. 01:00:47.520 --> 01:00:49.760 Go to pybit.es, our website. 01:00:49.760 --> 01:00:51.480 Check out our PDM program. 01:00:51.480 --> 01:00:55.240 And yeah, for anything, you can also join the PyBite Slack. 01:00:55.240 --> 01:00:57.720 Hit me up there with any questions or comments. 01:00:57.720 --> 01:00:59.760 I'm pybob, add pybob there. 01:00:59.760 --> 01:01:01.520 And I think that's it. 01:01:01.520 --> 01:01:02.160 Pybob? 01:01:02.160 --> 01:01:02.760 Yeah. 01:01:02.760 --> 01:01:03.920 That's a good name. 01:01:03.920 --> 01:01:04.400 I like it. 01:01:04.400 --> 01:01:05.040 It's on my handle. 01:01:05.040 --> 01:01:06.620 So yeah, perfect. 01:01:06.620 --> 01:01:09.300 So people can go check it out there. 01:01:09.300 --> 01:01:14.960 And you've got the cool aspects of the Spanish domain suffix. 01:01:14.960 --> 01:01:17.280 So pybit.es. 01:01:18.020 --> 01:01:19.840 You can actually have just the word. 01:01:19.840 --> 01:01:20.580 That's very cool. 01:01:20.580 --> 01:01:20.900 Yeah. 01:01:20.900 --> 01:01:21.520 Yeah. 01:01:21.520 --> 01:01:21.960 Excellent. 01:01:21.960 --> 01:01:22.460 All right. 01:01:22.460 --> 01:01:23.860 Well, thank you for being on the show. 01:01:23.860 --> 01:01:24.700 Thanks for writing the article. 01:01:24.700 --> 01:01:26.220 And good to catch up with you as always. 01:01:26.220 --> 01:01:26.240 Yeah. 01:01:26.240 --> 01:01:26.860 Thanks for having me. 01:01:26.860 --> 01:01:27.880 This was so much fun. 01:01:27.880 --> 01:01:28.900 I'm happy to share. 01:01:28.900 --> 01:01:29.260 You bet. 01:01:29.260 --> 01:01:29.720 Bye. 01:01:29.720 --> 01:01:30.280 Bye, everyone. 01:01:30.400 --> 01:01:30.680 Bye-bye. 01:01:30.680 --> 01:01:34.640 This has been another episode of Talk Python To Me. 01:01:34.640 --> 01:01:36.460 Thank you to our sponsors. 01:01:36.460 --> 01:01:38.060 Be sure to check out what they're offering. 01:01:38.060 --> 01:01:39.500 It really helps support the show. 01:01:39.500 --> 01:01:47.620 TypeI is here to take on the challenge of rapidly transforming a bare algorithm in Python into a full-fledged decision support system for end users. 01:01:48.120 --> 01:01:53.180 Get started with TypeI Core and GUI for free at talkpython.fm/typeI. 01:01:53.180 --> 01:01:54.620 T-A-I-P-Y. 01:01:54.620 --> 01:02:02.720 Stay on top of technology and raise your value to employers or just learn something fun in STEM at brilliant.org. 01:02:02.860 --> 01:02:08.940 Visit talkpython.fm/brilliant to get 20% off an annual premium subscription. 01:02:08.940 --> 01:02:10.940 Want to level up your Python? 01:02:10.940 --> 01:02:15.000 We have one of the largest catalogs of Python video courses over at Talk Python. 01:02:15.000 --> 01:02:20.180 Our content ranges from true beginners to deeply advanced topics like memory and async. 01:02:20.180 --> 01:02:22.840 And best of all, there's not a subscription in sight. 01:02:22.840 --> 01:02:25.740 Check it out for yourself at training.talkpython.fm. 01:02:25.740 --> 01:02:27.640 Be sure to subscribe to the show. 01:02:27.640 --> 01:02:30.500 Open your favorite podcast app and search for Python. 01:02:30.500 --> 01:02:31.740 We should be right at the top. 01:02:32.180 --> 01:02:36.900 You can also find the iTunes feed at /itunes, the Google Play feed at /play, 01:02:36.900 --> 01:02:41.100 and the direct RSS feed at /rss on talkpython.fm. 01:02:41.100 --> 01:02:44.520 We're live streaming most of our recordings these days. 01:02:44.520 --> 01:02:47.940 If you want to be part of the show and have your comments featured on the air, 01:02:47.940 --> 01:02:52.300 be sure to subscribe to our YouTube channel at talkpython.fm/youtube. 01:02:52.300 --> 01:02:54.200 This is your host, Michael Kennedy. 01:02:54.200 --> 01:02:55.500 Thanks so much for listening. 01:02:55.500 --> 01:02:56.660 I really appreciate it. 01:02:56.660 --> 01:02:58.580 Now get out there and write some Python code. 01:03:01.500 --> 01:03:19.220 I really appreciate it. 01:03:19.220 --> 01:03:19.520 I really appreciate it. 01:03:19.520 --> 01:03:19.540 I really appreciate it. 01:03:19.540 --> 01:03:19.600 I really appreciate it.