Applying the Scout Rule14:13 with Craig Dennis
Let's leave the campground cleaner than we found it.
So thanks for taking on that imaginary demo of our software with our 0:00 imaginary client. 0:03 I'm glad that we took the time to do that, aren't you? 0:05 As you know already, it turns out that once we fix the bug 0:07 things weren't working exactly like they wanted. 0:10 They definitely didn't like that the counting seemed strange and 0:13 some were getting seen more often. 0:16 However they did like the randomness of things With the current set up, 0:17 the same order is returned through each iteration. 0:21 So they were hoping that we could get some random shuffling of the cards. 0:24 That seems reasonable for a study app right? 0:29 Now this is a common issue, you fix some code and 0:30 the client likes how it used to work. 0:34 The lines between feature and bug can sometimes get pretty blurry. 0:36 I’m glad we're getting a chance to get back in there and clean stuff up. 0:41 I know it had me so confused that I had to actually walk a line by line. 0:44 I kind of felt bad leaving it that way for the next poor soul who had to come in and 0:49 decipher what it's doing. 0:52 Right now that only is living in our brains. 0:53 So there's a saying for what we're about to do, 0:56 here in the US we have a group of kids that we call Scouts. 0:59 They get together and they get taught things about wilderness and survival and 1:02 how to be a good human and all that stuff. 1:06 And they're separated into boy scouts and girl scouts, and 1:07 somewhere along the lines in coding a famous phrase 1:11 came up that mirrored one of the rules from the boy scout side of things. 1:14 Always leave the campground cleaner than you found it, so 1:18 the idea is you leave the campground clean because you are thinking about future 1:20 campers who will come and enjoy it. 1:24 You clean it up regardless of who made the mess 1:27 because you are improving the environment for future groups of campers. 1:29 So the idea is this, you always check in code in a better state than you found it. 1:33 The rule has been further documented as this. 1:38 Try and leave this world a little better than you found it. 1:41 And I can totally get behind that idea, and 1:45 in the spirit of making our shared world here a little bit better. 1:47 I'd like to reframe this lesson by not thinking about it 1:50 as the boy scout rule but how about just the plain old scout rule? 1:53 I'm positive that the girl scouts follow the same principle. 1:57 And by us talking on that boy part, it doesn't do much for 2:00 our fellow girl coders, and definitely doesn't handle the logic at all. 2:03 Women leave code better than they found it all the time. 2:08 So let's make a conscious decision to garbage collect 2:10 useless exclusionary words. 2:13 So ready scouts? 2:15 Let's go clean up this mess. 2:15 So let's go ahead and let's switch back to master. 2:18 Let's checkout master and I'm gonna pull, 2:23 since we committed there we're gonna update our project. 2:26 Cool, and then probably get rid of our old branches that we deleted. 2:33 Cool, all right, so let's 2:37 go ahead and let's open up a, 2:42 getNextFlashcardBasedOnViews, and 2:47 we wanna open up the, here we go. 2:54 Open up the definition of that, just in. 3:00 There is a service, FlashCardServiceImpl. 3:06 Here we go, let's scroll down this page. 3:12 I'm gonna go ahead and get rid of these repo things we have going on. 3:14 I wanna stop the debugger from running, so we don't have that going on, 3:19 I'm gonna clean up all the space, here we go. 3:24 So we want to get this what we getNextFlashCardBasedOnViews. 3:27 Boy, I've already kind of forgotten what it's doing in here have you? 3:35 Now part of the reason why that's hard to grop what's happening is because there 3:37 are multiple things happening. 3:42 So I like how descriptive this first call is. 3:44 It says getNextUnseenFlashCard. 3:46 We need something kind of similar for this stuff below here. 3:49 So when you start feeling that one thing that you should do is you can 3:53 highlight it and choose Refractor, and we're going to Extract > Method. 3:58 And so I like that least viewed ID, let's go ahead, 4:04 we can change this, we can make it public. 4:09 Let's make it public, and 4:13 how about getLeastViewedFlashCard. 4:17 So this looks better already. 4:26 We could probably flip this logic around a little bit to make a single return. 4:28 It feels like we can make it just 4:33 return once, so let's say, 4:38 we do this if card = null. 4:43 The card is going to equal this method. 4:47 And finally, we just return card so there's just one return. 4:51 Wow, look at that. 4:59 Look how much cleaner that reads. 5:00 Our scout leaders would be proud already. 5:02 It's super legible So let's do something about that randomness that they want. 5:04 Now I saw a pretty nice implementation earlier I think about shuffle and yeah, 5:09 here we go. 5:13 So why don't we shuffle our entries. 5:15 We'll get the entries out and we'll shuffle. 5:17 So let's refactor and extract our entry set from this for loop here. 5:19 So let's pull these out, so I'm gonna come out here and 5:25 we'll choose Refactor > Extract and we'll extract that to a Variable and 5:29 entries is fine, that makes sense to me. 5:34 And I don't think that you can shuffle that. 5:41 Let's try, let’s try Collections.shuffle(entries); sorry, 5:46 it's Collections.shuffle yeah, 5:53 Collections.shuffle(entries). 5:57 Let’s see, it says you can't do it to a set. 6:01 So why don't we just make a list, 6:04 then here we'll make a new ArrayList. 6:10 And we'll pass in this set that we were using before. 6:17 So now, we have shuffled entries and I'm going to comment this out here. 6:25 It can use, Cmd+Shift that, there we go. 6:30 So the algorithm here is really just about finding the entry with the smallest count. 6:35 So if we took a look over again at this getRandomFlashCards, 6:42 it's making use of these streams which I think are super powerful. 6:46 They're introduced in Java 8 and they really help you to do some 6:50 great functional programming, which is kind of what we're at right now. 6:53 So I think that we should probably follow the same style that the authors of this 6:57 originally were using. 7:01 We should try to dive into what they were doing. 7:02 We want things to read similar for people coming to our codebase, 7:05 especially in the same file. 7:09 These two are completely different ways of doing things. 7:10 So let's do it, so one thing that a stream can do is find the minimum 7:13 value in all the results and that is exactly what we want to do so. 7:18 So our results are entries, so let's go ahead. 7:23 We're gonna say return, we're gonna do entries and 7:25 we're gonna open up the stream() on it. 7:28 Now, the method that finds the minimum is called min, and 7:31 what the minimum takes is it takes a comparator. 7:36 So we can use a higher order function,which is 7:40 (Comparator.comparing) and that will return what we want. 7:44 It will return a comparator, that will compare two entries to each other. 7:49 And what we want to be compared is the count side of things. 7:53 Remember, we're comparing the value. 7:57 So we can use a method reference, because what's gonna come 8:02 through each one of these is, each entry is going to be compared to the next one. 8:08 So we'll do, (Map.Entry::), and then we're going to a method reference to getValue. 8:10 So minimum, you might think just returns the thing, but it doesn't. 8:18 It returns an optional value, 8:22 because it assumes that what happens if we don't have any values in there. 8:23 Streams are super cautious about no pointer exceptions. 8:27 So one of the things that optionals have is a really nice function that you can do 8:30 and it's called mapping. 8:34 So you can map what was passed in if it was passed in, we're gonna map that. 8:35 So we have an entry, that was key in the value and 8:41 we're just gonna do the same code that was happening down here before. 8:43 So it was using this findOne, so I'm gonna copy that, 8:47 And we're gonna do (entry.getKey). 8:53 Now it's possible, remember still this optional might not be here. 9:00 So to properly handle that let's go ahead and 9:06 we'll say orElseThrow, And you really shouldn't be finding 9:09 the least viewed card if you don't have anything in there. 9:14 You should be calling this method, so I'm gonna say that it's an illegal argument 9:19 except that we could probably make one of our own if we wanted to. 9:22 To make that a little bit more clear, but 9:25 what will happen here is it will throw an exception. 9:27 The exception will be thrown, so let's walk that one more time. 9:29 We're gonna shuffle everything that we know about these counts. 9:34 And we're gonna find the minimum of those values by comparing each of the entries 9:38 together. 9:42 Then we're gonna transform that into an actual card and 9:43 if we can't find it we're gonna throw an illegal argument exception. 9:47 Declarative program really shines here I think, 9:51 the imperative version of about 15 lines long. 9:54 But now we're looking at about three, and I think it reads pretty well. 9:56 There's more in the teacher's notes. 10:01 Now I haven't heard back from the client yet 10:03 about test, but this is so screaming for a unit test. 10:07 So a nice trick is if you wanna give your things a spin, 10:13 there's a nice little trick that the debugger offers you. 10:16 And I wanna show it to you because this is super handy when there aren't tests. 10:21 So here let's drop a break point win that method is called. 10:25 So the first time they haven't seen one, so we'll drop one right here, 10:31 we'll put a break point here. 10:35 Let's start the debugger up Run that I'm going to go over to up here, 10:37 I'm gonna clear our session, and we will just loop. 10:44 Oops. 10:49 Legal start of expression, Not the statement. 10:54 [LAUGH] this is the wrong side. 10:59 Sorry, there we go. 11:03 Let's restart the debugger again. 11:06 That's was pretty silly. 11:10 Sure you sit there screaming at me. 11:13 Fix that, you did it wrong! 11:16 So come over here, We got a new session and we're gonna flip through and 11:18 it should only kick off when it's in part where they're seen. 11:24 Cool, here we are. 11:27 So in this context we can click this evaluate expression. 11:28 And so we can call, where's the right place? 11:33 I think we have a trailing friend here. 11:38 Let's go ahead and we'll step into that. 11:43 Here we go. 11:48 So we'll continue on to our step here. 11:48 So we've got the LeastViewedFlashCard. 11:51 So we're about ready to call that. 11:55 So what you can do, cuz you can evaluate expressions, and 11:56 I'm gona flip this into code fragment mode so I get extra lines. 12:00 You can say getLeastViewedFlashCard and you can pass in idToViewCounts, 12:04 and we'll find out it should be one, should just be a random one. 12:09 So if we click Evaluate, we're gonna get that card, and if we click Evaluate, 12:13 we'll get another one. 12:16 So we can keep on running this thing. 12:17 Now what's super cool about this is we can make our own 12:18 map cuz we can create different things here. 12:23 So all we need is we need a map Longs to Longs and we can call it test, 12:27 we can call it whatever we want and we can make a new hash map. 12:31 And here you can do test.put and 12:35 we can as long as they line up with cards, we'll be okay. 12:38 So we can say, card1 and 12:43 we'll say that was viewed 15 times, and we can copy these. 12:46 And card2, 3 was viewed 2 times and 12:52 this was viewed 7 times and 12:59 4 was viewed 2 times. 13:05 So it should find the minimum, let's do one. 13:09 Let's do one first just to test it, then I'm gonna pass in a test. 13:12 So now we can evaluate and we're running that same thing. 13:18 So it's gonna find the smallest one is, at the moment 4, cuz it's 15, 2, 1. 13:20 And we can put in 2 here, and then we can click Evaluate. 13:26 And it should be finding different random ones. 13:33 Is the shuffle not working? 13:38 There we go. 13:42 Awesome, so we can make sure that things are behaving like we expect them to with 13:45 how a test framework there, even though there should be one. 13:49 Let's go ahead and click Close, and 13:52 I am going to mute all these breakpoints and continue. 13:54 Let's just take a look at it over here, make sure things are still working. 13:58 Here two times, three times JRE, YAGNI should be different order. 14:01 Perfect, it is. 14:07 Each time it's coming through we're getting a different thing. 14:09 We did it. 14:11
You need to sign up for Treehouse in order to download course files.Sign up