#150: Technical Lessons Learned from Pythonic Refactoring Transcript
00:00 Michael Kennedy: Does your code smell? Does it have a weird fragrance? It turns out code smells are a real thing and an amazing conceptualization of suboptimal design. This week you'll meet Yenny Cheung, who has some practical and real-world advice on using refactoring and Python to improve your code and wash away those bad smells. This is Talk Python to Me, Episode 150, recorded January 31st, 2018. Welcome to Talk Python to Me a weekly podcast on Python the language, the libraries, the ecosystem, and the personalities. This is your host, Michael Kennedy. Follow me on Twitter where I'm @mkennedy, keep up with the show, and listen to past episodes at talkpython.fm, and follow the show on Twitter via @talkpython. This episode is brought to you by ParkMyCloud and Rollbar. Please check out what they're offering during their segments. It really helps support the show. Yenny, welcome to Talk Python.
01:03 Yenny Cheung: Hey. Very excited to be on here.
01:05 Michael Kennedy: It's great to have you. I saw your talk, you know, virtually, via YouTube, PyCon.DE, and that was really really interesting so I wanted to make, give you an opportunity to come here and share your technical lessons learned from refactoring with everybody.
01:20 Yenny Cheung: Thanks, it was also a great learning experience for me with that many Pythonistas there and I also learned a lot from people's opinions. We had a great chat.
01:29 Michael Kennedy: One of the things I think is a little bit counterintuitive or ironic is probably when you see those presentations given, the person that learned the most from that presentation is the person presenting it, right?
01:40 Yenny Cheung: Yeah.
01:42 Michael Kennedy: Cause you had to do all the research and the thinking, and all that. It's not just what came out, but it's like the whole experience, right? Yeah, yeah, pretty cool. So, before we get, though, into the details of all the refactoring stuff that you talked about, which is really interesting, let's talk about your story. How'd you get into programming and Python?
01:58 Yenny Cheung: That's a long story. So when I was in high school, I don't actually know programming as a thing. I was just really into math and sciences. I like the problem solving part of it. I even like physics as a subject and from there I kind of know that I like the application side of things because I feel by doing those high school problems I can solve real world problems. Not really but that's how I got into it. And in university, very naturally, I just applied for engineering. I didn't really think about pursuing software engineering at all, because I didn't know it's a profession, but there's one requirement course that I need to take for engineering, and that was CS21, Intro to Programming. So after I took it.
02:42 Michael Kennedy: What language was that?
02:44 Yenny Cheung: That was in Python.
02:45 Michael Kennedy: Oh, okay! Nice!
02:45 Yenny Cheung: After that, taking that class, I think Python set a very high bar for me. So I didn't really get too much into other languages anymore, because of how much I liked Python. It's such a neat and beautiful language, I would say. So, yeah, pretty much after that class I decided to switch my major into computing science instead, and I dropped engineering.
03:08 Michael Kennedy: That's really wild. So, it really connected with you and you're like, "This is, I found something I like better." I think that's an important part of college, actually. I'm always kind of blown away that people just go into college knowing what they want, and they just do that, cause to me college was, you go and you try a bunch of things, and, you know, a few things connect, and you sort of follow that path. So what kind of engineering were you doing before you switched into programming?
03:33 Yenny Cheung: It's general engineering. We didn't really pick the discipline, yet. By the time I had to do that, I already switched out, so. didn't get to that--
03:41 Michael Kennedy: Oh, gotcha.
03:42 Yenny Cheung: part of it. I think it's a pretty smart thing to use Python as the first language to teach to people. Because I really feel like in Python you spend less time thinking about the syntax. You get to think more, much more, about the logic of the code and computer science itself. So, compared to other languages, which we learn later, like, C++, C, which are great cause, you know, you get more of the happenings under the hood. I think Python really took all these distractions out from the get go.
04:15 Michael Kennedy: I agree. I think it's a really good learning language. What surprises me about Python is there's a lot of languages that are kind of simple in that regard. Like, Visual Basic, like 6, you know, the early Visual Basics, and things like that. They were kind of like that, but they would always, they would hit this really hard limit soon as you tried to do very complicated stuff with them. And Python seems to have struck balance where it's simple in the beginning, but it can grow into larger applications, still?
04:41 Yenny Cheung: It's totally an art, how to write good Python code.
04:45 Michael Kennedy: That's for sure. What do you do these days?
05:08 Michael Kennedy: Of course, of course. And you work at Yelp, right?
05:10 Yenny Cheung: Yeah!
05:11 Michael Kennedy: That sounds like a really fun place to be.
05:13 Yenny Cheung: I think so. So, I work in Yelp in Hamburg, so not in the San Francisco office. We have three engineering offices. SF, London, and Hamburg. Here we focus more on the business side of things, so selling ads, helping local businesses find customers, and things like that, which I find, I find it to be very interesting. Yeah, like, I really enjoy being here.
05:37 Michael Kennedy: I'm sure. Is Yelp pretty big in Europe? I only know it through the US. When I lived in Germany I didn't actually use Yelp very much.
05:44 Yenny Cheung: There are definitely some competitors in Europe, as well, but it's growing, it's getting its ground.
05:50 Michael Kennedy: You actually have more offices in Europe-
05:52 Yenny Cheung: Yeah!
05:52 Michael Kennedy: Which is kind of cool, right, London and Hamburg.
05:54 Yenny Cheung: Well it's like, good thing about working in a European office is you get to fly around in Europe, you know?
06:00 Michael Kennedy: I know.
06:00 Yenny Cheung: You get to go to all these, like, fun European conferences, which is very nice.
06:04 Michael Kennedy: That's one of the things I really liked about being there is you're so much closer to many amazing places to visit. Where I live in Portland, it's three hours to Seattle, to the north. It's 10 hours to San Francisco to the south, and it's eight hours to Boise to the east, and those are the three closest cities. You're in Paris in two and a half hours, or you're in, you know, Vienna. It's really just such a different experience there, so, enjoy it, that's cool.
06:32 Yenny Cheung: But like the tech scene, I would say it's, like, very much concentrated in the US. Like, say, SF, you have such a huge technical community. But in Europe it's definitely more spread out, so you need to, like, fly from one place to another, maybe like a bigger tech hub would be Berlin? But still, it's really, really widespread.
06:49 Michael Kennedy: That's an interesting observation. Cool, so, let's talk about your topic that you covered at your talk, which is refactoring. And I think refactoring, it's interesting that we've had programming, what you might consider programming, maybe since the 60s? Right, d'you consider punch cards? I dunno. But we've had programming for quite a while, but refactoring as an idea, didn't really come out until, I dunno, was it early 90s? Mid-90s, something like that? Like the whole Martin Fowler thing? Yeah, so. Yeah. It finally got sort of formalized an idea. So maybe just really quickly, for everybody listening, cause I know people, you kind of use refactoring and just changing your code to be better and maybe adding features, and what not while you're doing it, as interchangeable. So maybe just quickly give us, like, a definition of refactoring.
07:41 Yenny Cheung: Code refactoring is pretty much the process of restructuring existing computer code. That's pretty much meaning changing the refactoring without changing its external behavior. And it also improves the non-functional attributes of the software.
07:56 Michael Kennedy: From the outside it should appear as if it didn't change, but you might change the way the algorithm is implemented or something to that effect, right?
08:06 Yenny Cheung: Pretty much changing the design, like, improving the design of it, but without changing the functionality of what your software is supposed to do.
08:14 Michael Kennedy: Book that kind of announced that was Martin Fowler's book, and you talked a little bit about that in inner talk as well. And I just looked it up, it was published in 1999. I mean, that's like, height of dot com, boom days, right? It seems pretty far down the line for when that came into existence.
08:30 Yenny Cheung: This is kind of like, I dunno, the Bible for refactoring? In a lot of ways, I feel, it's like a start of discussion, but in a way, a lot of those principles can still be still applied to other languages, and in other situations. I would really like to use this book as like an introduction to what refactoring means. But later on in the podcast I think we must also touch on Python might not need that many of these refactoring patterns.
08:57 Michael Kennedy: Right, so, one of the things that was interesting, you know, so, there was a lot of stuff that came around the same time. Martin Fowler's refactoring concepts, we had Kent Beck and I think maybe Martin Fowler was also participating in that with sort of extreme programming, iterative programming. We had the whole design patterns and the Gang of Four book. There were some really interesting foundational ideas brewing in that time. Certainly the design patterns, thinking, and, it seems like just from looking at Martin Fowler's work, that it's very much based on languages like Java, or Smalltalk, or these heavily object oriented, I dunno, sort of object only languages.
09:42 Yenny Cheung: Right.
09:42 Michael Kennedy: I think it's interesting to compare that back to Python because it doesn't always make sense, or there's problems you'll find in Python that don't appear in the list of, say, the code smells which we'll talk about at the refactoring techniques, because they're, it's fundamentally a different way to structure code in Python.
09:59 Yenny Cheung: I would totally agree with that. Like, a lot of the problems that the refactoring patterns try to solve, I think, inherently in Python's language design, it's already solved. So, we can definitely explore into that a little bit later.
10:12 Michael Kennedy: Right, and then, at the same, yeah, I think another one, though, so, for example, that I think is kind of an issue you might run into is what, I dunno, I would call it's like a long module or something, right? Where everything is just crammed into one file and it probably should be broken apart to be more easily understood, right? But that doesn't appear anywhere in the traditional literature, because, they're talking about things like Java where you just have one class per file, so if the file is long that means the class is long, right? But that's not necessarily the case in Python. I feel like there's, like, refactoring obviously applies to Python, but some of the traditional history of it is maybe an 80% match.
10:56 Yenny Cheung: I would agree, like, a lot of the ideas translate, but like, how you achieve that might change because of the language and how to apply that.
11:03 Michael Kennedy: For sure. All right, so let's start by thinking about just why? What are the benefits of refactoring?
11:10 Yenny Cheung: So, first of all, I think it cleans up tech debt. For those who are not as familiar, tech debt tends to build up when you take shortcuts during development, there might be a better solution, but instead you took, like, a shorter one so that you can save some developer time. But these trade offs, you need to pay, pretty much like pay for a debt, later. You need to spend more time to fix the implementation, and things like that. Or it may be when you have the spec, it's not complete yet, or you know, the products change, the code changes. So, the thing you design right now might not be applicable for the future? And in this case refactoring really helps it get into shape again. But I just think that it's a good habit to have. Whenever I write a function, it's very few times that I can get it right the first time. So upon, thinking a little bit more about it, or I look at it the next day, there can be a lot of improvements can be done. Maybe you can extract it to the function, name it better, things like that. And also I just think that it really saves productivity cause I've worked on C code before, and my experience was, I come to work, I look at all these code, and I finally I understood what it means. The next day I'll start implementing new features. Then I go home and I had a nice sleep, I came back and then I just forgot what it does. And the code doesn't really help because it's so convoluted. So, imagine that, but like times 10, the whole team pretty much does the same thing. If some people can be responsible for refactoring this, then everybody doesn't have to face the same problem.
12:47 Michael Kennedy: It's almost like a golden rule of programming in a professional environment is you talked about the boy scout rule which was--
12:56 Yenny Cheung: Yeah.
12:57 Michael Kennedy: Let's leave the place, in this case the code, in a better state than we found it every time we interact with it. So that's a pretty interesting idea.
13:05 Yenny Cheung: That was one of the first things they'd tell us at Yelp. It's a common courtesy. You don't want to hand worse code to your colleagues than you found it. So that's where the boy scout rule comes from.
13:17 Michael Kennedy: That's pretty cool. I think another real world analogy applied to code that would be appropriate there would be the broken window theory. So for those of you don't know about that, that's in, I believe it came out of New York City, and there used to be, the city was kind of run down, and there was a lot of crime, and they said, "What can we do to make these neighborhoods nicer?" and there was some psychologist or something that realized that just a few broken windows and a little bit of decay sort of communicated to the people of that neighborhood that, "Oh, this place, we don't care what it's like. It's kind of broken, and what does it matter if we break it a little bit more?" Whereas if you come upon really nicely factored code that's really clean and beautiful to read, you don't want to go in there and mess it up, right? The expectation is, if I'm going to contribute to this, this is beautiful. I'm not going to just throw junk on it, right? So, I think that's an interesting psychology about it as well.
14:09 Yenny Cheung: That's a very good analogy. And at the same time, I like what Martin Fowler mentioned in his book. He said he's a lazy developer, so the fact that he's working on this code right now means that it's very likely for him to work on this in the future. So it, just, refactoring right now makes sure he can understand it easier, you know, in the future.
14:28 Michael Kennedy: Yeah, yeah.
14:29 Yenny Cheung: A lazy developer is a good developer.
14:32 Michael Kennedy: Productive laziness.
14:33 Yenny Cheung: Exactly.
14:34 Michael Kennedy: You said, also, in addition to cleaning up technical debt, it'll actually save you productivity now and over time, right?
14:42 Yenny Cheung: I would agree, because after refactoring, supposedly your code should look simpler, increase the readability. In this case, the code can also be more usable and easier to maintain, and it's good for you. This is the good thing about Python. Python already reads very, very nicely, I would say, like its semantics is very easy to read. So if you can write good Python code, your code pretty much self-document, and that's a huge win. Imagine an organization, like Yelp, right? We have over 300 microservices? And then we have even a monolith of code based. There is, it's impossible, for you to write documentation to cover every line of what you write, right? So in this case, if you can write code that is readable, that is easy to read, then onboarding new people, if they, if you have like a new hire, an intern in your team, then, they can immediately jump on. Like it really, I think it really brings a lot of value to the team.
15:44 Michael Kennedy: This portion of Talk Python to Me is brought to you by ParkMyCloud. The last time you parked your car, did you leave it running? No? Well, then why are you leaving your cloud resources running? Every year, 13 billion dollars are wasted on cloud instances that no one is using. Don't let any of those be yours. ParkMyCloud automatically identifies and eliminates wasted cloudspend, saving you 65% on AWS, Azure, and Google's Cloud. You're up and running quickly with a 10-minute setup, and no scripting required. Plus, govern users and easily integrate into your DevOps process. See why ParkMyCloud was chosen by McDonald's, Unilever, Fox, and more. Start a free trial today at parkmycloud.com/talkpython. So you talked about these 300 microservices and some monolithic code as well. How do you guys think about, say, refactoring from one larger service into microservices? Or maybe the reverse, maybe taking five microservice, these are really not doing enough to be independent things, so we're going to smush them back together.
16:54 Yenny Cheung: Whenever we build new features, definitely, like it's always in the back of our mind, "Can we make that into a separate service? Can we modularize it a little bit better so that we don't have to contribute code to the giant monolith?" But, yeah, at the same time, you know, if you have more microservices, there is always overhead, so it's really a decision that you need to find a good balance between it I would say.
17:17 Michael Kennedy: For sure. There's definitely trade offs there. Another benefit to refactoring, I think, is maybe overlooked? I'm not entirely sure how, how often, say, managers, take this into account in business, decision makers. It seems to me as a developer working at a company, if you always work on code that seems to have no care, no craft, it's just kind of thrown together and not well-factored, you might decide either you'll be unhappy or you might just leave, and so, maybe we're actually losing your best developers because they don't want to work with the crappy code. So refactoring it for all the reasons you already talked about, cleaning up debt and stuff, it seems like it almost could be an HR issue.
18:02 Yenny Cheung: For sure. Who doesn't like to work on clean code, nicely designed code?
18:07 Michael Kennedy: Exactly. I've certainly worked on some projects where I'm like, "Wow, this does not look fun to work on, why do I... What is even going on here?" Crazy variable names and huge stuff crammed into one function, or--
18:22 Yenny Cheung: Right.
18:22 Michael Kennedy: something, right?
18:24 Yenny Cheung: For sure.
18:24 Michael Kennedy: Another benefit, maybe, what do you think? Flexible software?
18:28 Yenny Cheung: I think there are different thoughts into how you should write software. Because some people think that software as kind of like a throwaway thing. Because products evolve so quickly, that your code probably doesn't live very long. After one year, two years, you have to rewrite it. Things come up and you look at code that is supposedly to be very well-designed before but two years after it's not. Code tends to rot. One thing about refactoring is the thing you, that came out from refactoring should be easy to modify. So, I think refactoring actually complies with this thinking. If it's easy to read you know exactly what to change, you know exactly what to throw away, and that's very important.
19:10 Michael Kennedy: Absolutely, a lot of the refactoring stuff also applies to breaking things into smaller, more well-understood pieces. Instead of one huge log function, maybe like a couple of functions, and, like a class that represents the data, or something so it actually just makes it easier to evolve and change over time, anyway.
19:33 Yenny Cheung: A counter-example, the CSS, you know, you can only add lines to it and not really take it out, because you don't know, once you take out something it breaks. So this is exactly the situation we want to avoid.
19:45 Michael Kennedy: That's a really good way of thinking of CSS, and I definitely noticed that, because you're like, but what about that one page that nobody realized is there, or there's that admin section and you don't want to redesign that, so, maybe, you know, maybe, I find, like, the changes go into, like the bottom of the CSS file, or if it gets really out of control, you'll create like a this page overrides those CSS settings, and we'll include that file after this one, right?
20:13 Yenny Cheung: I think it's like a nightmare. Recently I'm working on the React project, which makes it better, because you have CSS modules, but these theories of modularize your code, can apply to every language, even CSS.
20:26 Michael Kennedy: Do you use anything like Less or Sass? Or just straight CSS?
20:31 Yenny Cheung: We do use Sass as well, but, I think the good thing about CSS module is you can declare, you know, this element is what needs this class, so, in a way you can know exactly what is used and what is not used.
20:44 Michael Kennedy: Right. the dead selector stuff you're doing-
20:47 Yenny Cheung: Yeah.
20:49 Michael Kennedy: It's even worse than regular code.
20:50 Yenny Cheung: Yeah.
20:51 Michael Kennedy: That's sort of the benefits of refactoring. When do you think we should refactor? What are some of the best times in sort of the software lifecycle?
21:01 Yenny Cheung: I think, yeah, that's a very good question. I think it's really an iterative process. So whenever you add code, remove code, when you're understanding code, when you're fixing bugs, those are always very good timings for it. And another thing I would also want to point out is during code review. If after this podcast you're more into this refactoring thing, during read code review, then maybe you can comment, "Hey, actually, you can do this better." and you can raise the code quality for your entire team. I would really want to push for the value of code review.
21:36 Michael Kennedy: I think part of this might be deciding what's important during code review, right? Like are you reviewing for performance? Are you reviewing just for our code standards? Are you reviewing for correctness? This sort of cleanliness aspect of refactoring probably would make a really good checkbox in the review process.
21:59 Yenny Cheung: Definitely. I've also read up some articles on how to do code reviews and your suggestion is perfect. I think it's assigning one reviewer to review that part of the code or that aspect of writing code, is very helpful. It can also come with one problem with refactoring is say if your whole team is all very enthusiastic about refactoring and you can imagine how much ideas people can have, asking you to rewrite the code, and it can also get into not so great of a situation, cause you'll have a lot of iterations, right? One suggestion can be having several people in a design, involving several people in a design phase, to come up with something, and then one person can be responsible to work with the person who's writing code, to do refactoring. That tends to streamline the process a little bit.
22:52 Michael Kennedy: I think, also, there's probably what you might consider microrefactorings versus we're going to change the whole architecture, right? Like "I have some long function, I broke it into three, and I changed the parameters to be more clear." versus, "Oh, this actually should be another service. We should use queuing here, and let's make the database NoSQL." and that's another level, right?
23:13 Yenny Cheung: I think that's definitely like a do later. Let's follow up on that. But that's the thing about refactoring on the legacy system versus a new project. Definitely it's much harder when it comes to a legacy system, especially code that you're not familiar with, code that some other people wrote. There are so many things that you think you can improve, but how do you, you know, when do you start, and when do you stop? It's important. You can't just, like, it's a black hole. You can't just continue doing factoring until the end of time. So I think it's important to time box yourself as well. One suggestion will be, say like this week, I spend one day on this, and I'll wait a bit, I'll learn a little bit more about the code, and the next week I'll come back again, and do another day of refactoring.
23:59 Michael Kennedy: You could probably do a couple of interesting things. You could probably run things like flake8 against it, or other, you know, there's probably not just pure refactoring problems, there's probably a host of problems. So, you could approach it, sort of, "I'm just going to make it a little bit better "every day, until it's not so bad."
24:20 Yenny Cheung: Right, the boy scout rule.
24:21 Michael Kennedy: Exactly, apply it to this. One particularly tricky challenge with legacy systems, I think, you know, this typically happens at larger organizations, is there's some not very high profile project, but it's somehow really important that if it stops working it's going to be a big problem. Some kind of backend thing or something. And the person who created it is either no longer on the project, or left the company.
24:50 Yenny Cheung: Right.
24:51 Michael Kennedy: It's written in, like, you know, Python 2.5, or some old thing. And it's not currently your problem, but you would like to make it better, but you know if you break it it's you problem, all of a sudden, right? Like if you try to make it better and you break it, you now own it, because it was working and you're the one who made it not work, and who even knows how to deploy this thing again, right? That can be a really--
25:11 Yenny Cheung: That sounds like a government problem.
25:14 Michael Kennedy: Yes. I've definitely seen this at some big companies. There's actually a book I want to give a quick shout out to, about this legacy system in particular called Working Effectively with Legacy Code by Michael Feathers, and he has some really interesting ideas of how to basically take a huge, existing system and partition off little parts you're going to change and make them testable, flexible, refactorable, without overwhelming, without trying to, you know, boil the ocean and change everything all at the same time. So, it's pretty cool. A lot of techniques there.
25:48 Yenny Cheung: Cool, I'll definitely check it out.
25:50 Michael Kennedy: It's really cool. It's, unfortunately, a lot of it is sort of C and Java, but the ideas in there are really interesting. I mean, some of them are so insane, it's like, "We're actually going to change the way the linker works to trick the system to do certain things consistently while we're making other changes in the C." I mean, it's really quite far out there. But there, you're like, "Oh, I didn't even think that we could take it that far." and there's a lot of, I'm sure people get good ideas from it, even if it's not in Python.
26:17 Yenny Cheung: For sure.
26:18 Michael Kennedy: Another problem that I think you run into around this kind of improvement but no features, has to do with selling this idea to your manager. And I think while a lot of the modern software development methodologies are really nice, like, Scrum, for example. The concept of a sprint in a two-week or a month-long sprint, you're going to sign up for some work, right? Well, where does refactoring fit? If I'm already fully booked on time, how do I go and say, "I'm actually going to do only half as much because I'm going to make things better. Well, we actually just need new features. This is really important so forget the better." All right, how do you have that conversation, do you think?
26:59 Yenny Cheung: I think it's a very important conversation to have. But the fact that you're thinking about refactoring, when you're adding new features, you sense that something is wrong, that might be an indication that we need to do it right now. So I think the way to communicate with the product manager, or with your engineering manager, is "Hey, if we don't do the refactoring right now, it's actually going to take six weeks. But if we do the refactoring, spend one week on it, it'll be easier to add features, so four weeks." I think that usually communicates the idea across.
27:30 Michael Kennedy: I find that does work sometimes. What I've done in certain circumstances where it was like, "Look, we're just really busy right now. We just need to go fast, and we'll deal with it later." sort of mentality. It wasn't super as explicit as that, but where that's kind of implied you know what I mean, where it's, it's clear that the people would much just rather have that feature right now. But that was, if that seemed like it was always the case?
27:57 Yenny Cheung: Yeah.
27:58 Michael Kennedy: It's sort of like if everything is urgent then nothing is urgent. It's kind of like that, right?
28:03 Yenny Cheung: There is also the tech debt thing, right. We need to deal with it later if we keep on building out this tech debt. It's not like we don't have to do it never.
28:12 Michael Kennedy: Yeah.
28:12 Yenny Cheung: It's going to come back to you. It's going to haunt you one day.
28:14 Michael Kennedy: Absolutely. I feel like that will work well in place like Yelp where it's a pretty technical company, but let's say, I'm just going to--
28:21 Yenny Cheung: Definitely.
28:22 Michael Kennedy: completely make up a company that I don't really know whether their technical or not, but let's say I work for a food production company that sell, makes like cereal, right? Those managers probably don't know or care about what technical debt is. They just want the new feature for their website or something. What I've found in those situations, I would just start adjusting my estimates to include--
28:45 Yenny Cheung: Yeah.
28:46 Michael Kennedy: refactoring and testing. Instead of saying, well, I'm going to spend this much time on the feature, and this much time on refactoring, this much time on testing, I'm going to say, "This feature takes x." And just--
28:54 Yenny Cheung: Exactly.
28:55 Michael Kennedy: If I'm going to work as a professional developer, that means refactoring and cleaning up technical debt, and putting it in test, and these sorts of, and you ask how long it takes, this is how long it takes. All right, you just don't say it's done and--
29:06 Yenny Cheung: Right, you're giving your professional opinion, I totally agree with that.
29:09 Michael Kennedy: I think you've got to adjust maybe per what kind of environment you're in, but it's--
29:14 Yenny Cheung: Yeah.
29:15 Michael Kennedy: It is a little tricky to say, "I'm going to take a bunch of time and do nothing, in terms of what you see that we get. I'm going to not do anything, right?" But of course it's actually making it much better for all the reasons we talked about, right?
29:27 Yenny Cheung: Exactly.
29:28 Michael Kennedy: I do think that your warning earlier was really interesting, though, because there's absolute possibility that you just go refactoring and patterning crazy and just go, "All right, we're going to keep changing this, and keep changing this." and only see this get, it could really be un-ended. So, I guess one of the things that might be interesting to talk about is, when do you know that you should refactor, and how should you go about that?
29:55 Yenny Cheung: This is a very interesting topic. So, in the same book, actually, Kent Beck coined the term of code smell, so pretty much means it's a surface indication that usually corresponds to a deeper problem in the system. So, I would like to make a metaphor with cheese. Sometimes, the key word of this is the indication. So sometimes cheese can smell very strong, especially those French cheese. Then you think there is something wrong but when you eat it, it's actually good. Code smell is an indication of a problem, but you really need to take some time to investigate into it, if it's actually a problem. Say you have a very long function, but it actually does one thing. So, okay, perfect.
30:38 Michael Kennedy: This concept of a code smell has absolutely, just like, captured my imagination when I first heard of it because it so perfectly captures what is wrong. It's like, if you look at some code and your nose kind of wrinkles up, you're like, "Ugh, look at that." It works! It's actually working just fine, but to get in there and to be with it is a little unpleasant? That is just the perfect idea of this, this code smell, right?
31:02 Yenny Cheung: Well, that's the thing, like, you know, any programmer can write things that machine can compile, but then only good programmers can write code that humans can read.
31:12 Michael Kennedy: Absolutely. I think, what's interesting about the code smells is it's not just, like, hey, there's this idea of a, of smelly code, but there are actually smells, flavors of smell? Like types of smells that then are prescriptive of different refactorings, which is super interesting, and that's kind of what we were talking about at the beginning, where some of the smells are more applicable to, say, Java, than they are to Python, but still, there's plenty of Python analogies here. Before we get into the code smells, one thing that also Martin Fowler talks about that just, I think is so perfect, is he talks about the idea of code comments being deodorant for code smells.
31:54 Yenny Cheung: I really like that analogy. If you have a lot of comments on your code, then that probably indicates that you didn't write it very clearly. That's why you need to write comments to explain yourself. So it's important to know that when you write a comment you should address why you're writing this, but not what you're trying to say. If it's a what problem, then maybe you should rename it, or try to use some variables to explain what you're trying to do here.
32:21 Michael Kennedy: I think this might be the most important idea of this entire code smell thing, is, literally every time I go to write a comment I stop and go, "Why am I writing this comment? Is it really that I should just stop and rename the function? Is the function badly named? Are the parameters badly named? Is the function too big?" And so, I could break it into smaller pieces so each one can then be really clearly-named because right now it seems like the name would be a paragraph. Right, all of those types of things.
32:47 Yenny Cheung: Right, exactly.
32:49 Michael Kennedy: People all the time try to fix these with code comments and it's just like, just delete the comment, make the variable name three characters longer, but understandable, right?
32:58 Yenny Cheung: Exactly. Totally agree.
32:59 Michael Kennedy: That's awesome. All right, so, maybe take us through some of the various code smells and how we might fix them.
33:06 Yenny Cheung: Sure. I can vaguely categorize them into a different classes. So, first you have long and complex code, you have useless code, coupled code, and inappropriate naming. I think we can go through them one by one. So let's start with the long and complex code. Sometimes in your program you can see very long functions and classes. That might be an indication that your class or function is not doing one thing. Just one thing. That violates the single responsibility principle. The DRY principle, Don't Repeat Yourself. In this case, maybe we can extract the function or classes so that everything is encapsulated well. When you're doing this, when you're using this technique of extracting functions, though, beware of pass by reference, versus pass by value. It's like, this mistake, everybody makes, and you pass in the dictionary, rather than just viewing, just getting it, you're modifying what is inside, and you know the list, dictionary, they're immutables. It's very dangerous, it's evil.
34:10 Michael Kennedy: You do have to be careful about that. I think this is probably one of the most common things you run into, as just, something started out small, and it grew, and it grew, and it grew, and nobody wanted to really mess with it. They just wanted their feature in there, and so, they added a little bit more. You know, another if clause, another conditional, or whatever, right?
34:31 Yenny Cheung: Adding new keys to your dictionary, you don't even know, and you would like, pass by, you passed in the dictionary, and the end, it, the dictionary totally got muted, and it's very hard to keep track in this way.
34:42 Michael Kennedy: For sure.
34:43 Yenny Cheung: And some other long and complex code problems, as well, say, temporary field? That pretty much means you call a function and you cast it into a variable, but sometimes if you're not using this variable for a few times, you can just call it in line. Otherwise it gets really confusing, and when you're trying to extract functions, those are the things that can prevent you from doing it very simply. And one other thing I want to point out is the conditional complexity, which I think most developers probably encounter it, needs too. You know, you just want to write something very simple, if else, and you ended up having three or four layers of nested, conditional logic, and that's just really, really hard to read.
35:23 Michael Kennedy: I find that people do that a lot because they... Oh, what's the right word? They're testing for success, so, I'm going to say, I'm going to do a loop, and then, if this thing I want to work on is true, then I'm going to go into that part, and then if this other condition also is true, I'm going to go, and you end up, like, almost scrolling right just to read what the code is doing, you know?
35:46 Yenny Cheung: That's where the line limit came in for PEP 8, I guess, you know, but 79 is very, very strict, I would have to say, you can probably modify it for your own need. But that could possibly stop people from writing too long of a code. Maybe you were trying to encompass too much information on one line.
36:03 Michael Kennedy: For sure. Well, and people are looking for something concrete, like, "Okay, I know this is not good, but, what do I do?" Like, you can reverse the if statements. You can do what's called a guarding clause that'll say--
36:14 Yenny Cheung: Right.
36:15 Michael Kennedy: if it's not good, either skip this time of loop, or return early, instead of, if yes, yes, yes, if yes, if yes, you just go with no return. If not this, return, if not that, return. And then what's flat below is the actual thing you want to do, that can really help.
36:30 Yenny Cheung: Exactly. Guarding clause is a good way to go. And in here I would even value simplicity and I would even sacrifice the shortness for the conditional complexity. So, even being more verbose, having more verbose statements, I think it would help, instead of introducing the nested conditionals.
36:52 Michael Kennedy: Yeah, nesting is bad.
36:53 Yenny Cheung: Exactly, I think that's also mentioned in The Zen of Python, you have flat is better than nested.
36:57 Michael Kennedy: Yeah.
36:59 Yenny Cheung: So it's good to remember that.
37:01 Michael Kennedy: Just import this if you find yourself three levels deep.
37:04 Yenny Cheung: Exactly.
37:07 Michael Kennedy: This portion of Talk Python to Me has been brought to you by Rollbar. One of the frustrating things about being a developer is dealing with errors. Relying on users for report errors, digging through log files, trying to debug issues, or getting millions of alerts just flooding your inbox and ruining your day. With Rollbar's full stack air monitoring, you get the context, insight, and control you need to find and fix bugs faster. Adding Rollbar to your Python app is as easy as pip install rollbar. You can start tracking production errors and appointments in eight minutes or less. Are you considering self-hosting tools for security or compliance reasons? Then you should really check out Rollbar's compliant sass option. Get advanced security features and meet compliance without the hassle of self-hosting including HIPAA, ISO 27001, Privacy Shield, and more. They'd love to give you a demo. Give Rollbar a try today. Go to talkpython.fm/rollbar and check 'em out. So, what are some more, in this area?
38:05 Yenny Cheung: As we mentioned, the mutable problem. Using dictionary as a param is pretty dangerous. We just now we talked about why. So I would suggest using named tuple. Because that's the thing, if I see a function, and I'm debugging something, I see it passing in as a param, I'll probably cry a little bit inside. So, it's just, like, a location, right? I have so much imagination in my mind. Could it be like a latitude, longitude, like, is it a number, a string? Could it be like city, country? I have no idea. I need to throw in a debugger, I need to try to run the program and see what exactly is inside. But if you use named tuple, it's defined. You know exactly what is inside. And when it comes to Python 3.6 that's type annotation. So, really, like, no questions asked, you don't have to guess anything. I think it's a very good way to go to prevent a lot of the work that has to be done and prevent bugs.
39:02 Michael Kennedy: I really like that suggestion. It's great because it takes this kind of unknown thing and captures it into something that, you know exactly what's there, how to access it, and the type annotation reinforces that that is actually the thing that's going there.
39:16 Yenny Cheung: Exactly. So you don't have to worry about the... Because it's immutable, you don't have to worry about it being changed, so less bug will be introduced.
39:25 Michael Kennedy: That's true. Very very cool. Another one that I want to throw in here that does not have a code smell, but I want to give it a name and I'll run this name by you see what you think. You know, you talk about dictionaries parameters, that's kind of hard. When I see a method that takes *args, ** kwargs, it's just like, I'll just take anything. You name it, you don't name it, I don't care. Just give it to me, like, I'm just like, "Oh my goodness. What do I do here?" I had such a hard problem switching data centers in S3 because I needed to change the encryption mode? It was like the craziest thing, with the Boto API. And I went to look in the, it was like this, and I went to look at the documentation, and one of the kwargs was itself a dictionary, which only had a name, it had no description of what even goes into the dictionary. I'm just like, "How do I, I'm supposed to do this?" So my proposed code smell name for those types of methods are starry calls.
40:20 Yenny Cheung: Perfect. You're coining the term today. Starry call, I like it.
40:23 Michael Kennedy: Starry call, there you go.
40:25 Yenny Cheung: Some people call it black magic, the kwargs that got passed in. I guess the power, the structure of Python, it really lets you do so many powerful things. But at the same time you really have to be responsible about it, because with great power comes great responsibility.
40:41 Michael Kennedy: For sure. I understand why these methods sometimes exist but I feel like a lot of times people are just like, "Well, it's easier than just making people name the orders, and we'll just let 'em put whatever and we'll figure it out." That doesn't actually help them use it. You know what I mean?
40:55 Yenny Cheung: Exactly.
40:56 Michael Kennedy: So the next section is useless code.
40:58 Yenny Cheung: Right, so as you mentioned, too many comments is definitely a deodorant. Definitely we should write down why, but not what you're trying to do. If that's the case, then you probably should consider renaming, or explaining it. One very common one is just the duplicated code. So adhering to the DRY principle, you should extract functions, or considering an inheritance... Well, in Python you have other ways to do it as well, which we might cover later, is the composition pattern which might work a little bit better in Python's case. And sometimes you have debt code, well, because your code is not modularized. It's very hard to tell if your line is being executed. But there are some IDEs that are smart enough to tell you if the code is not executed or if some variables are not used, so that can be a good help. Or sometimes you have lazy classes. So, you have this one class that doesn't really have any functions, only have some fields, same, yeah, like, pretty much some fields. And in this case, you can just replace it with a named tuple and that just makes things easier, cause maintaining classes takes energy, it takes time.
42:08 Michael Kennedy: Actually, named tuples use less memory than a regular class, anyway, so, it's probably slightly more efficient.
42:14 Yenny Cheung: I would agree.
42:15 Michael Kennedy: Yeah, so one tool, these are all great, and they all can drive me crazy. I've spent untold hours getting hold of some project, looking at some method, going, "I don't understand how this is working in this environment, it really seems like this doesn't work." And so I'm trying to understand this code, and then it turns out that after a lot of piecing stuff together, I'm like, "Oh, the reason it doesn't seem to have any effect is because it's never called." Oh my god.
42:44 Yenny Cheung: Oh no.
42:44 Michael Kennedy: It's just so frustrating. It's a little bit of the broken window syndrome. It's just people left it in there, but they were afraid to take it out, right?
42:53 Yenny Cheung: Yeah, the CSS.
42:54 Michael Kennedy: Exactly, it's like the CSS problem. The other one I want to give a shout out to, which is really, it's just like, it's so delightful, is in PyCharm, you can open up a huge project, let's say it has like 100 files, you don't have to select anything or do anything. You can just go to a menu, I can't remember where it is, but you say, "Find duplicate code." and it'll compare blocks of, it'll just go, "Oh, this sort of test here is done, actually, in 20 places. You could just make that a method."
43:20 Yenny Cheung: Yeah.
43:20 Michael Kennedy: And that's pretty cool. Cause you don't have to guide it. You just say, "Go find the duplicates." and it'll, somehow put that all together.
43:25 Yenny Cheung: I love all these, like, tools that can help us refactor code. It's awesome.
43:29 Michael Kennedy: For sure. So, what's the next section?
43:31 Yenny Cheung: We'll talk a little bit more about coupled code. So, you have something called the message chains. Pretty much means function a calls function b, and then function b calls function c, so when one thing changes, say, in the chain, function c changes. There is a ripple effect, so everything has to change. All your functions have to change. And for functions that have this message chain problem, it's very, very hard to test. So, in this case, you know, the productivity is just drained away from first writing the function, understanding the function, and then writing tests, which is really not great.
44:07 Michael Kennedy: That can be one of those problems where you try to make some small change down at some lower level and it, like, cascades through every layer of the application. You feel like you're changing so many files just in order to, like, well, like let's take an example, like, I want to add an extra parameter to the creation of an object way down low. Well, that means the method that calls that has to pass it, but the class that calls it doesn't have it, so its constructor has to take another parameter which, and it just creates this, like, this sort of combinatorial explosion of like, "Why am I just doing this everywhere? This is crazy!" Right?
44:41 Yenny Cheung: I would totally agree. So, like, if we can flatten it out a little bit, maybe function a can call function b and then function a can call function c, that'll make it a little bit better and easier to test.
44:53 Michael Kennedy: For sure, or, maybe even there's some other mechanism from getting that information, deep down there, like, maybe it's stored in the database instead of passed, or, I dunno. It really depends, but.
45:03 Yenny Cheung: Yeah, or it creates static functions, those are always great. Pure functions. They're dumber, it's easier to test.
45:10 Michael Kennedy: I dunno what to make of the next one: indecent exposure.
45:13 Yenny Cheung: Oh, it's very clear. It's exposing your privates. To other classes.
45:16 Michael Kennedy: That sounds very indecent, yes. That's right.
45:19 Yenny Cheung: If your class is consistently calling, like, functions from another class, then it's better to combine it, probably. So that means you have code that's too modularized, in a way, that maybe if they share the same context they should be put together.
45:34 Michael Kennedy: That's an interesting comment, because I feel like one of the things that's funny about refactoring and the code smells is they often have what I want to coin as refactorial inverses, right? Like multiplicative inverses, right? Like there's inline variable, and there's create variable. There's inline method, there's, you know, extract method, there's, you know, push this to subclass. Pull it down, pull it to subclass? Push it to all the derivative lines, you know, like these, there seems to be, like, this thing and this undoing thing often in refactoring, and it really is context-driven, right?
46:09 Yenny Cheung: That's why I say it's an iterative process, because once you have added some code, the situation is different again, and maybe what could be code smell before is not a code smell now. Or, if you, upon investigating, the code smell actually doesn't point to anything. So it really, you know, it's a constant effort, I would say, to keep your code good along the lines.
46:31 Michael Kennedy: It's also why you can basically refactor for infinite time, because you can--
46:35 Yenny Cheung: Right.
46:36 Michael Kennedy: do the thing, and then you undo the thing, and then you do the thing in a different way.
46:40 Yenny Cheung: Yeah.
46:41 Michael Kennedy: So the last section you wanted to cover in this area was inappropriate naming.
46:45 Yenny Cheung: I would love to cover this area because it's one of the three hardest problems in computers, right? You have in cache invalidation, you have threading, and then you have naming.
46:56 Michael Kennedy: That's right. And this is something I care a lot about as well, like, it's kind of really, closely tied to the code comment stuff, and so on.
47:03 Yenny Cheung: That I would totally agree because Python is dynamically typed, so in a way, when you create a variable, it doesn't really have the type information stuck to it, and in this case, you know, with great power comes with great responsibility, we need to name things right because we kind of didn't have this, some extra information as other languages would have had.
47:25 Michael Kennedy: Naming variables correctly. Naming modules correctly. One thing you recommend are keyword arguments, or at least calling functions in the keyword argument style, right?
47:35 Yenny Cheung: Definitely. So, in this case, you don't have to have like 10 terminals opened to see the function definition when you're stumbled upon its code, right? Immediately you know what is being passed into the function. So I think it's just a more efficient way, cause it's always good to be explicit than implicit, by the Zen of Python.
47:53 Michael Kennedy: For sure. Another thing that I think is, can be challenging is sort of, implicit values or magic values, so what I mean by that it's like, you had an example around a function that took the mood of a person and the mood could be like one, two, three, or the sets of numbers, and, is three good? You don't know, right? It's really hard to understand that stuff, right?
48:17 Yenny Cheung: I would totally agree. It's definitely indicating the direction is important, right? So mood bigger than three, what does that mean? Is it happy? Is it sad? So, casting it into a variable, call, is happy equals mood bigger than three? Can have a wonderful effect of documenting your own code.
48:34 Michael Kennedy: For sure, and Python recently added enumerations as well. Enum classes. And if there's only four moods, you know, making that an explicit enumeration, so there's like a sad sort of blase, I don't really care, like, then there's happy and super excited. I think it would be really clear that way, and it'd be a pretty good refactoring, too.
48:54 Yenny Cheung: For sure.
48:56 Michael Kennedy: So, this is all well and good and I would like a better list of Python code smells to guide us, but there's still plenty to work with from sort of the existing literature and writing and stuff. So, how do you go about developing your code nose?
49:13 Yenny Cheung: I definitely agree on reading literature on this but I think it's just a skill that you develop over time. So, if you actually just look at some legacy code you can find a bunch, for sure. And just seeing it day-to-day, you know, like, just read more of that and try to refactor more of that, I guess, we can learn at which point we need to refactor this, is this an indiction of a problem? It really comes with experience, and also the code review process can help you learn from other people in your team, or, you know, whoever is reviewing.
49:47 Michael Kennedy: I think the code review process is super helpful, if, at least, that's being incorporated into the code review.
49:52 Yenny Cheung: Yeah.
49:53 Michael Kennedy: If you're working more on your own and there's plenty of people who work, even in companies, but there's, they're kind of more or less on their own, they're not in a technology company. That code review can be more or less absent. And so, one of the things that came to mind while you were thinking about this, is like, or you're speaking about this, to me is, there's all these code smells. You could take, like, one code smell a week and say, "All right, I'm going to work on the conditional complexity problem this week." So any time I'm writing code, if I see, I feel myself writing that fourth indentation bubble, I'm going to, like, remind myself to apply this refactoring, or this technique, and you could just take them one at a time, right? Because they seem overwhelming all together, but they're pretty simple by themselves.
50:35 Yenny Cheung: That's definitely a good idea.
50:36 Michael Kennedy: One of the dangers of refactoring, I mean, it's extra high in legacy systems, but in general, it's a danger, is that your intention is to refactor code, but your actual outcome is you've changed code, right? It behaves differently. So what's the role of testing, here?
50:51 Yenny Cheung: I think testing is very important in the workflow. So what I would suggest is writing integration tests first for the code you're about to refactor, if it's not present yet. Then during your refactoring process after you extract the function, after you've changed the variable names, run it over again to check if that functionality of your codebase has changed. So that really helps you to limit loss after you change one thing, it's very easy to spot out what has changed. And after refactoring is done, you can start introducing unit tests to test that the functions you've introduced actually uses the right logic. So, with this workflow, I think we got our ground covered.
51:31 Michael Kennedy: That sounds like a good, a good way to do it. And what test framework? Do you use like, a built-in one? Do you use pytest, do you use nodes?
51:38 Yenny Cheung: Yeah, at Yelp we definitely have a built-in one, but there is pytest as well, which is very, very similar. You can just assert things, you know, there are a lot of in-built functions that you can use. Also one thing that Python is great, is you can use mocks, so that's, you know, if you have a network call that you don't want to actually make during your testing, then you can mock things out, and that's really, really convenient.
52:01 Michael Kennedy: Very nice. So, maybe let's talk about some of the tools that you could apply here because in Martin Fowler's 1999 book, he literally shows you the manual steps at every level. First you create this variable, you put this piece here. Then you do this step, and it's really painful but there's more we can do these days, right?
52:24 Yenny Cheung: I do think so. So, well, one thing is, you know, the styling part of it first. So we have PEP 8, right? PEP 8 is a Python enhancement proposal that talks about, it's essentially a Python style guide. So, how you're supposed to structure the white spaces, how do you comment things, how do you use the string quotes, things like that. So that, there are a lot of tools that can help you. There's the pep8 tool, there's flake8 that can also help you check conditionals, as well, I believe.
52:54 Michael Kennedy: Does it check for things like dead code, and stuff like that, as well, like unused parameters, or methods not called? Yeah, that's big.
53:00 Yenny Cheung: Yeah, or Pylint, and there are a lot of things that we can use that can be programmatic about it. I would want to mention Raymond Hettinger's talk. He was mentioning how PEP 8 can become a nightmare because you just have someone from the team that bugs everyone about, "Hey, your trailing comma is off. Your white space is off." But there's actually tools that can do that, and also, you should PEP 8 onto thyself, not to bug everyone in the team about it. It's like a style guide.
53:30 Michael Kennedy: Yeah.
53:30 Yenny Cheung: And it should serve like one, right? Because, if at the same time, you're pissing off your colleagues, or if readability is not improving because of this style guide then maybe it's not worth it to do it in the first place.
53:43 Michael Kennedy: You mentioned his Beyond PEP 8 talk. That is really quite insightful, it's a good example of how, just, following strict rules can lead to actually less readable code. Whereas if you let it slip just a little bit, but you're creative about it, there's actually better ways, or maybe even not so much that you break PEP 8, but that PEP 8 is not the end. There's actually more important stuff to think about than PEP 8 about how you structure code, where there's more Pythonic in the way that it works. It's a really good talk.
54:15 Yenny Cheung: I think it's done during PyCon, as a PyCon talk, Beyond PEP 8. One thing he also mentioned is rather than thinking too much about PEP 8, maybe you should think about the problem P versus NP. So, silence, what is the P what is the NP. It's Pythonic versus Not Pythonic.
54:35 Michael Kennedy: That's right, that's right. Cause you could write perfectly PEP 8 compliant, very non-Pythonic code, or you could just think beyond it and actually make the code better. Yeah, it's a good talk. And it was at PyCon, I believe, in that, so, there's a video version which I'll try to add in the show notes for people.
54:52 Yenny Cheung: I really like that talk.
54:54 Michael Kennedy: So, Yenny maybe that's a good place to leave it for the refactoring stuff, directly, but this was super interesting the talk about. Thanks for sharing your thoughts on that. One thing I did want to point out to people, folks ask me often about, where to get jobs, and, how to get into Python, maybe they're doing C and they want to, like, move over to a place that actually does Python. So, you at Yelp, you guys are hiring, right?
55:18 Yenny Cheung: Definitely, we have so many empty seats to fill and we really want you to be here. We use a Python backend. We have over 300 microservices, and we have millions of search requests per year. There are a lot of interesting projects, data, for you to play with, so, definitely. We would love to have you here.
55:37 Michael Kennedy: It sounds like a fun place that cares about code quality and craft, very nice.
55:40 Yenny Cheung: We have offices in San Francisco, or if you want to go to Europe, as well, we have London and Hamburg.
55:47 Michael Kennedy: Cool. All right, so before we get out of here, let me ask you the two questions. So, if you're going to write some Python code, what editor do you use?
55:54 Yenny Cheung: Well, since I'm a full stack engineer, I would actually suggest using Cloud9. I dunno if you've heard of it before, so it's pretty much you can code on a browser. It's super easy to set up, you can just git clone the whole repo into whatever environment you're working with, and you can pair programming real time. And it's just seamless for full stack development. Good for Python down to CSS, it's great.
56:17 Michael Kennedy: That's really cool. I really like the real time collaboration. It's sort of like Google docs for code.
56:23 Yenny Cheung: Yeah, definitely. And it's in the cloud, so you can pick up your progress wherever you left it.
56:28 Michael Kennedy: You could code on your iPad if you want.
56:30 Yenny Cheung: Perfect.
56:33 Michael Kennedy: That's right, and then notable PyPI package? What's one that's out there that maybe people didn't know about, that is pretty cool?
56:39 Yenny Cheung: Just now we mentioned pep8 or flake8. They're a pretty cool lens that can help you get your quote quality there. And, yeah, I think definitely you should check out The Zen of Python, because I think it's pretty much the key rules of this Python language. There are a lot of things that we covered already, like flat is better than nested, simple is better than complex, or with ability counts. But whenever you make a decision, when it comes to writing code, then, when in doubt, import this.
57:08 Michael Kennedy: That's perfect. All right, final call to action: people are excited to get started with refactoring and do it better, what would you say to them?
57:16 Yenny Cheung: Just start right now. You don't need a lot of tools, you don't need anything. Start reading materials, start learning the patterns or code smells one by one. I think it's a fun journey ahead.
57:27 Michael Kennedy: I totally agree. Thanks for that and thanks for being on the show. It was great to talk to you.
57:30 Yenny Cheung: Thank you. It was great.
57:32 Michael Kennedy: Yep, bye. This has been another episode of Talk Python to Me. Today's guest has been Yenny Cheung, and this episode has been brought to you by ParkMyCloud and Rollbar. Do you hear that sucking noise? That's you cloud provider making you pay for your idle instances. Turn on ParkMyCloud, plug the leaks, and save money. Visit talkpython.fm/park to get started. Rollbar takes the pain out of errors. They give you the context and insight you need to quickly locate and fix errors that might have gone unnoticed, until your users complain, of course. As Talk Python to Me listeners track a ridiculous number of errors for free at rollbar.com/talkpythontome. Are you or a colleague trying to learn Python? Have you tried books and videos that just left you bored by covering topics point-by-point? Well, check out my online course Python Jumpstart by Building 10 Apps at talkpython.fm/course to experience a more engaging way to learn Python. And, if you're looking for something a little more advanced, try my write Pythonic code course at talkpython.fm/pythonic. Be sure to subscribe to the show. Open your favorite podcatcher and search for Python. We should be right at the top. You can also find iTunes feed at /itunes, Google Play feed at /play, and direct RSS feed at /rss on talkpython.fm. This is your host, Michael Kennedy. Thanks so much for listening. I really appreciate it. Now get out there and write some Python code!