Mastering PyCharm Transcripts
Lecture: Finding duplicate code
0:01 Let's kick off this refactoring session by first looking at the structure of our code.
0:05 I still have or git repo up here, it says project course,
0:09 which is not amazing, we'll fix that in a minute.
0:11 And I've just decided to create one project that opens all of it,
0:14 and I have copied in this slightly altered Wizard code from my Jumpstart course
0:20 remember, it's called the wizard code,
0:22 because over here we have Creatures and Wizards which derive from them
0:26 and we have Small Animals, and we have Dragons, things like that.
0:31 So it's a little game, we're going to make this game a little bit better,
0:35 partly by removing some issues I've introduced.
0:38 Let's just say we haven't really looked at this code
0:41 and I would say probably the most significant issue
0:43 you're going to run into with refactoring is duplicate code.
0:46 Second to that, maybe tied with that is extremely long methods
0:51 or extremely large classes that should be broken apart,
0:54 and it turns out the solution for both of those is really often the same.
0:59 So, let's start on the duplicate code side.
1:02 Now, if we look at refactoring up here,
1:04 you'll see there's a hotkey that always let us refactor anything,
1:08 so if I was down here and I highlight this,
1:10 I could hit CTRL T on Mac, I think it's something else on Windows,
1:18 we can pick, extract variable, extract the constant,
1:22 extract a parameter, all these different types of things here.
1:25 But let's take a moment and not necessarily use this,
1:30 we could extract different things, pull members up and down, move,
1:33 we'll talk about what that is, change a signature methods and so on.
1:37 But before we apply the refactoring, let's ask where is the problem?
1:41 Is there a problem?
1:43 Well yes there's a problem, there's always a problem with code,
1:45 the question is— is it significant enough that a change will make it better?
1:50 Alright, so watch this— we go to code,
1:52 this is a pretty amazing feature, locate duplicates.
1:57 Now, if we run this, and we pick the whole project,
2:01 we could do one file or whatever;
2:09 So we're going to use Python, and you can anonymize certain things like
2:13 look for the same structure but ignore the details
2:17 of say like a string and a number
2:19 but if you're taking a string and a number to it
2:23 and then doing something else, then it's always the same that sort of series,
2:26 if I were to check this that would signal as a duplicate.
2:29 So we've got our options set here
2:31 and we can just go and run it and watch this
2:34 bam— across this entire project, we have found two sets of duplicates,
2:40 check this out here, let's see if we can make a little more room.
2:44 If we open this up in Actors, in the Wizard
2:47 and we can actually jump between them
2:50 so over here, we are in the Dragon,
2:53 notice there is a little hierarchy which is really sweet,
2:55 this is kind of new in PyCharm.
2:57 So we're in the Dragon, and in the init we're checking if the level is less than one
3:01 and in Actors, over in Creature, we have the same thing.
3:07 So this is not the most amazing thing,
3:10 we're actually doing this exact same test twice,
3:13 and let me open up the dragon here,
3:16 it turns out, whoever wrote the Dragon class
3:19 decided they want to check to make sure the level is good
3:21 but they didn't realize this is actually being called here as well,
3:24 so there's no need for us to call it here
3:26 because this line will already raise this value error,
3:29 so we can just remove that duplicate,
3:31 and let's run our find duplicates again.
3:33 Alright, now we're down to this one set of duplicates
3:40 but there's three of them and notice,
3:43 I can use these little arrows to change
3:45 like if I want to and do a diff, this one against that one over here,
3:48 so you can like move these arrows around, pretty cool.
3:50 So it says these are identical, they don't have to be identical,
3:53 but notice there is this representation that appears multiple times
3:59 and if we just jump to it, you'll see that what we're doing is
4:04 when you print out a Small Animal it says
4:06 here's a creature of this level and with this name.
4:09 But the dragon does the same thing and the wizard does the same thing,
4:12 but they all derive from Creature, so what we would like to do
4:16 is move this sort of just into the Creature
4:20 so we could come down here and the Wizard has the same problem,
4:25 so let's just focus on the Wizard for a minute.
4:27 So down here, I could hit CRTL T to refactor
4:30 and I could say pull members up in the hierarchy.
4:33 So what I'm going to do is I am going to
4:35 automatically move this from the Wizard into the Creature,
4:39 so it's part of the base class.
4:41 Hit that— boom, done.
4:44 So it's out of the Wizard, if I look at the Wizard the Wizard just has attack,
4:47 and now, we have the Creature there init
4:53 defensive role and now they have this representation,
4:56 and because it's in the base class, and it's the same,
4:59 the Small Animal doesn't need it,
5:02 and the Dragon doesn't need it explicitly
5:04 because they all derive from Creature
5:07 and if we run it, it should still totally work fine, let's see.
5:10 We run it, a level 12 Tiger has appeared,
5:14 we are going to attack that, a Dragon has appeared,
5:17 so you can see this is the little print, the representation thing,
5:21 I think somewhere around here, it's showing up.
5:25 But the idea is we can use these duplicate code plus refactoring
5:29 to improve our code and it's fine on this little example of two files
5:35 but if I had a hundred files, you would see this would be way more valuable
5:39 because it would make sure the whole thing was hanging together.