Introducing Code Katas 0:00If you've never heard of the term kata within the context of development, well, think of it as sort of exercise for coders. So if you're a musician, a guitar player, your exercise would be doing scales. And that doesn't mean that you're performing these scales for public. Instead, these are little exercises that are meant to improve everything from your focus to your strength to your workflow. So for our first kata, why don't we tackle the prime factors challenge, which was, if I remember correctly, first popularized by Uncle Bob. So what are the basic rules? Well, we need to use TDD to build a prime factors class where we can feed it a single Prime Factors Examples 0:34So what are the basic rules? Well, we need to use TDD to build a prime factors class where we can feed it a single number and that'll return a list or an array that contains all prime factors for that number. And just to make sure that we're all on the same page, let me give you a quick demonstration of what a prime factor actually refers to. So imagine that you have the number 4. Well, you probably know that a prime number is one that is divisible by itself and 1. So if I want to figure out the prime factors for 4, well, I need to figure out the sequence of the lowest numbers that it is divisible by. So as an example, let's do 2.of the lowest numbers that it is divisible by. So as an example, let's do 2. Is 4 divisible by 2? Yes. So 2 times 2 is 4. And in this case, that's all there is to it. So the prime factors for 4 are 2 and 2. Or how we might represent that in code is an array of 2 and 2. Let's do another one. 5.Let's do another one. 5. Is 5 divisible by 2? Nope. What about 3? Nope. Let's go up the prime number chain. Is it divisible by 5? Yes. So that means 5 would return 5.Yes. So that means 5 would return 5. Let's do another one. 6. Is 6 divisible by 2? Yes. So 6 divided by 2 is 3. So 2 times 3 is 6. And in this case, we can't break it down further than that. So that means the prime factors for 6 are 2 and 3.And in this case, we can't break it down further than that. So that means the prime factors for 6 are 2 and 3. Let's do just a couple more to make sure that everyone's on the same page. What about 10? Is 10 divisible by 2? Yes. 10 divided by 2 is 5. So now we have 2 and 5. For 12, 12 divided by 2 is 6. But now 6 is not a prime number.For 12, 12 divided by 2 is 6. But now 6 is not a prime number. Can we break down 6 further? And the answer is yes. So is 6 divisible by 2? Yes. So 6 divided by 2 is 3. So now we can see that the prime factors for 12 are 2 times 2 times 3, or 2 squared times 3. Finally, let's do one more larger one, and then we'll get going.3. Finally, let's do one more larger one, and then we'll get going. 50. Or how about 100? All right, let's start with 2 again. Is 100 divisible by 2? Yes. So that's 2 times 50. Now we can, of course, break down 50 further. 50 is divisible by 2, so that would be 2 times 25.Now we can, of course, break down 50 further. 50 is divisible by 2, so that would be 2 times 25. And then we can do 25. Now 25 isn't divisible by 2 or 3. And an easy way, by the way, to figure out if a number is divisible by 3 is to add up the numbers. So 2 plus 5 is 7. Is 7 divisible by 3? No. However, if you had a number like 33, well, 3 plus 3 is 6.No. However, if you had a number like 33, well, 3 plus 3 is 6. Is 6 divisible by 3? Yes. Then 33 is as well. That's a little trick there. Anyhow, for 25, you probably know that's 5 and 5. So that means the prime factors for 100 would be 2, 2, 5, and 5. And if we add that up, it works. 2 times 2 is 4. Setting Up PHPSpec 3:39And if we add that up, it works. 2 times 2 is 4. 4 times 5 is 20. And 20 times 5 is 100. Alright, so hopefully we're all on the same page. Now we can tackle this. I'm going to be using PHPSpec and TDD here, and I already have that pulled in, so we can jump right in. Let's describe prime factors. And now let's run it.Let's describe prime factors. And now let's run it. We need to create the prime factors class. Luckily, PHPSpec will do that for us. And now let's run it one more time, and we do get green. Now to keep myself from having to run that over and over, I have this gulp file that I use. We built this right here on LairCast, so if you'd like to review that, I'll add a link in the show notes. But that means I can now type gulp, and this will automatically trigger my tests, as well Building With TDD 4:21in the show notes. But that means I can now type gulp, and this will automatically trigger my tests, as well as give me a notification. So the first thing is, I'll get rid of this and clean this up for our purposes. Okay, so what does it do? And using TDD, we can start with the absolute basics. So for example, it returns an empty array for 1. So on this prime factors class, let's say this generate 1 should return an empty array. Okay, so we run this, and of course it fails. So now I'm going to switch over to my test, and let's get started on this.Okay, so we run this, and of course it fails. So now I'm going to switch over to my test, and let's get started on this. We need a method called generate, and that'll accept a number. So now we need to think about the rules here. Remember, when we were doing these code katas, it's way less about actually coming to the solution, because honestly, I probably have a basic idea of how to come to this solution. However, it's less about that, and more about thinking about the mindset, and thinking about the workflow. As an example, how am I specifically following these rules of TDD, red, green, refactor? And specifically, how can I make these cycles as short as possible?As an example, how am I specifically following these rules of TDD, red, green, refactor? And specifically, how can I make these cycles as short as possible? Also while I'm doing this, I can focus on more general stuff, like my editor-specific workflow. So remember, this isn't about coming to the conclusion as much as it is about your workflow and your practice as a developer. Anyhow, in this case, what's the least amount of code we can write to make it pass? So if we expect an empty array, then why don't we just return an empty array? And we should get green, and we do. Now we can move on to the next one.And we should get green, and we do. Now we can move on to the next one. And what you'll find is that, as we add more tests, we'll have to extend our code to make it more flexible. But right now, we just want to get back to green as quickly as we can. And that's what I mean by short cycles. So now, let's do the next one. What about if we feed it two? Well, it's going to return two for two. Now, when I call the generate method, and I give it two, then I expect to receive anWell, it's going to return two for two. Now, when I call the generate method, and I give it two, then I expect to receive an array that contains a single value of two. So we run it. Of course, it fails. So now, I need to make it pass. Once again, what is the least amount of code I can write to make this pass? And what I'm thinking is, what about something like this? If number equals two? Or we could even say, if number is greater than one, then return two.If number equals two? Or we could even say, if number is greater than one, then return two. Now, you and I both know that this is pretty elementary, and it's going to change. But it's about following this process. The least amount of code we can write to get ourselves back to green. And then once you're at green, when you decide to do so, you can start refactoring. Let's do another test. What about three? Well, it returns three for three, because three is a prime number as well. So this generate three should return three.Well, it returns three for three, because three is a prime number as well. So this generate three should return three. And now, of course, that's going to fail. So let's stay on this path just a little bit longer, and then we will do some much-needed refactoring. So if number is greater than two, then we return three. Or like I was saying, if you want to just be explicit there, then we can do that as well. All right. But now, once again, we're back to green.All right. But now, once again, we're back to green. So now I want to get up to four here. Function, what are the prime factors for four? Well, that's two and two. So it returns to two for four. And let's do our test. When I feed it four, now I should receive two and two. So this is a little bit different. And while, yes, we could do things like if number equals four, let's go ahead and makeSo this is a little bit different. And while, yes, we could do things like if number equals four, let's go ahead and make that work, clearly you can see at this point this breaks down very, very quickly. But that's okay. We're at green. So now we can take a break and start refactoring. First, I want you to notice that I have all of these different returns. So already we're at four returns for a single method. Not the best idea. Instead, why don't we create an array up here?Not the best idea. Instead, why don't we create an array up here? Why don't we call it primes and set that to an array? Now we can update all of these to primes equals. We're still going to change this, but I want to make little changes to get back to green. And then finally, return the primes variable. But now we're still getting at green. Why is that? Well, that's because we're no longer returning. So we said if number equals four, then set the primes array to the correct set of data.Well, that's because we're no longer returning. So we said if number equals four, then set the primes array to the correct set of data. But then we have all of these other checks where it still passes. So ultimately, our factorizing of four is returning two, and that's not what we want. Well, why don't we do this? I'm going to go back to my test and temporarily comment out this one. And now, rather than doing all of these checks, what if we say if number is greater than one, then why don't we just append to the primes array the number? Now I can get rid of all of this stuff right here, and hopefully we still get green. And we do.Now I can get rid of all of this stuff right here, and hopefully we still get green. And we do. So now I've made a small change. It's okay to comment out this last one. But now I can bring it back and continue forward. So now let's go back and figure out the fourth one. Now it's true, we could pull that back in and then do something like an else if. And that'll get us to green. However, I know it's still going to break down as soon as I move up to five and six and eight. So we're still at green. Using Modulus Operator 9:45However, I know it's still going to break down as soon as I move up to five and six and eight. So we're still at green. I'm going to do another layer of refactoring. And the key in this situation will be to use the modulus operator. Let me give you a quick example of how that works, if you're not familiar with it. Let's switch over to Chrome, and I will use the console here in Development Tools to quickly show you the output. Now, if I were to say, how about 4 modulus 2, what is it that we're saying there? Well, basically we're saying, is there anything left over after you divide 4 by 2? So 4 by 2 is 2. There's nothing left over, so we get 0.So 4 by 2 is 2. There's nothing left over, so we get 0. And the same would be true for 6 modulus 2, or 6 modulus 3. But what about something like 6 modulus 4? Or you could say 6 mod 4. Well, in that case, 4 goes into 6 one time with 2 left over, so we get 2. And the same would be true for 6 mod 5. In that case, 1 will be left over. So let's do one more just to make sure everyone's on board. 12 mod 2 would be what?So let's do one more just to make sure everyone's on board. 12 mod 2 would be what? Well, is 12 divisible by 2? Yes, so we get 0. 12 mod 3? Is 12 divisible by 3? Yes, so we get it again. The same will be true for 4. But now 5, 12 is not divisible by 5. So 5 goes into 12 twice with a leftover of 2.But now 5, 12 is not divisible by 5. So 5 goes into 12 twice with a leftover of 2. And that's what we get. So now that we have a simple little equation to figure out if a number is divisible by 2 or 3, we can take advantage of that. Let me show you. Let's say if the number provided, mod 2, equals 0, then we know the number provided is divisible by 2, so we can add 2 to our primes array. So I can say primes equals 2. Now this is going to still fail.So I can say primes equals 2. Now this is going to still fail. Let's see why. Well, we have 75% passing, but it's failing on this one right here. So we expected to get 22, but instead we just got 12. So why is that? Well, let's try it out. Imagine that we feed this number 4, and I'm just going to update all of these to make it more readable. Then we begin by saying if 4 mod 2 is 0, it is, then we add 2 to our primes array,it more readable. Then we begin by saying if 4 mod 2 is 0, it is, then we add 2 to our primes array, and then we immediately return the primes array. So that just returned 2. Not what we want. So it sounds like what we need to do here is change this from an if to a while statement. Something like while the number provided, mod 2, equals 0, then we want to add 2 to the primes array. However, we need some way to reduce this. So what if we tried this?However, we need some way to reduce this. So what if we tried this? Number and divide it by 2. Now I can bring this back right here. And we're back to green. So what happened here? Well, we fed it 4. 4 is divisible by 2, so we added 2 to the primes array. But now we want to break it down and divide very much like we did in the example at the beginning of the video I showed you.But now we want to break it down and divide very much like we did in the example at the beginning of the video I showed you. So now I'm saying take that 4 and divide it by 2 and assign it in the same process. So now number is equal to 2. Then we run it again because we're in a while statement. Is 2 mod 2 equal to 0? Yes. So now we add another 2 to the primes array, which means this is now 2 and 2. Finally, we divide 2 by itself, and that brings us to 1. Is 1 mod 2 equal to 0?Finally, we divide 2 by itself, and that brings us to 1. Is 1 mod 2 equal to 0? No. So we're done in the while loop. Now we just have our final check. Is the number greater than 1? If so, then set that equal to the number and return the primes array. And we get green. Now we're going to keep working on this, but why don't we move on to the next test. So we have 4.Now we're going to keep working on this, but why don't we move on to the next test. So we have 4. What about 5? Well, it returns 5 for 5. So this generate 5 should return an array with one item in it. And check it out. That one just works right out of the box. Let's do another one, 6. It returns 2, 3 for 6. Now if I generate 6, I want that to return 2 and 3.It returns 2, 3 for 6. Now if I generate 6, I want that to return 2 and 3. And that returns green as well. Now let's do another one. How about it returns, we're going to do 8 here. So 2, 2, and 2. Those would be the prime factors for 8. And let's say this generate 8 should return an array that contains 2, 2, and 2. Now we're starting to get cocky here, but be careful. Let's try 9.Now we're starting to get cocky here, but be careful. Let's try 9. The factors for 9 would be 3 and 3. So 3 and 3 for 9. And if I call generate 9, then that should return an array of 3 and 3. But now we run it, and crap, it fails. So let's check it out. So we tried to run this, and we expected an array of 2 items, but we just got 9. So we just returned an array that contains 9 in it. Actually that's not what we want.So we just returned an array that contains 9 in it. Actually that's not what we want. So we need to fix this. What's the problem here? Well, we get to 9 and we say, is 9 mod 2 equal to 0? Or is 9 divisible by a 2? No it's not, so nothing here fires. And then we say is 9 greater than 1? Yes, so just set the array to 9 and return it. Not the correct thing to do. Generalizing Factor Algorithm 15:05Yes, so just set the array to 9 and return it. Not the correct thing to do. So how can we fix this? Well here's what I'm thinking. So why don't we grab this 2 here and extract it to a variable. And we could call this anything from candidate to divisor, whatever you think is most readable. But candidate is pretty common here. Alright, so now I can update these 2 as well. And our tests are still failing, but only because I need to refactor a little bit. So I'm going to comment that out to bring us back to green, and that way I have a littleAnd our tests are still failing, but only because I need to refactor a little bit. So I'm going to comment that out to bring us back to green, and that way I have a little more confidence that the changes I'm making here aren't breaking any code. So what exactly have we gained here? And right now, not really anything. Candidate is still equal to 2. However, what if when we were done here checking to see if the number is divisible by 2, we could bump up to see if the number is divisible by 3? What might that look like? Well let's see.What might that look like? Well let's see. Right now, don't worry, we're still at green. Why don't we add another loop here, and we'll say while the number is greater than 1, only then do I want to do all of this stuff right here. If it's not greater than 1, then we don't need to bother. Next, after we've done all of the checks to make sure that the number is divisible by 2, I'm going to increase candidate by 1. And that way, we can do the whole thing over again to see if the number is divisible by 3.And that way, we can do the whole thing over again to see if the number is divisible by 3. And now you can see we're back to green. And even better, because we're now doing the check to see if the number is greater than 1 there, maybe I can get rid of this stuff entirely. Let's try it, and we get green. So now notice the power that gives us. Because I have these tests backing up every single assertion, essentially, I try to make, I can make these changes with so much confidence without having to, for example, open a browser to test out whether this is working.I can make these changes with so much confidence without having to, for example, open a browser to test out whether this is working. That's pretty cool, and trust me, once you get into this, you won't be able to imagine how you were able to refactor before you had this test suite backing you up. So now we're at green, so I'm going to bring back this test, and if we run it again, awesome! So this refactoring has made our code that much more flexible. Even better, I'm thinking that basically our algorithm is done, other than some last-minute tweaks. So let's use our class to factorize 100 like we did at the beginning of the video. It returns 2, 2, 5, and 5 for 100, and if we try it out, hopefully, we'll get green.So let's use our class to factorize 100 like we did at the beginning of the video. It returns 2, 2, 5, and 5 for 100, and if we try it out, hopefully, we'll get green. 2, 2, 5, and 5. Run the tests, and we get green. Good job. So now we're sure that the algorithm works. At this point, if you want to do some final tweaks, we can do that. How might we improve this just a little bit? Well, this Candidate++, that's sort of a dead ringer in my mind that we might need to use a for statement instead.Well, this Candidate++, that's sort of a dead ringer in my mind that we might need to use a for statement instead. So how about we begin up here? We want Candidate to equal 2, so I don't need to initialize anything. And then, as long as number is greater than 1, then let's increase Candidate by 1. So now I can get rid of this entirely, and if I save it, yes, I'm still at green. Next, if I have a place to initialize Candidate, why don't I just do it right here, and then I can remove that line entirely. Save it. I'm still at green.Save it. I'm still at green. Finally, I'm thinking for the second while, the same might be true, because we're basically checking for a condition, then doing something, and then finally adding, like we did before, or in this case, dividing a number. So maybe I can change this to 4. There's no initialization, so I'm going to say, as long as number mod Candidate equals zero, then number divide equals Candidate. And I can remove this line entirely. I'll save it.And I can remove this line entirely. I'll save it. Still at green. And you know what? I think that's about as good as we can hope for. So I add my doc blocks, and now you've used TDD to solve your very first code kata. Congratulations.