 Video equipment rental costs paid for by peep-code screencasts. Hi, I'm Jake Speggs. I work at Abtivo, and I'm here to tell you about how to use metrics to improve your code quality. Your code is in red to emphasize that it's not just other people's code that's bad. So I should just say that I come from a very lucky special place that I used to teach high school physics, and then I sort of got an apprenticeship at Object Mentor, and I turned that into a gig at Bow Works, where I did six projects, and now I'm a consultant at Abtiva. And that is just a great place to learn about code. Like all these places are known for just being kind of ludicrously obsessed with like what's good quality. I mean especially Object Mentor right there. They're all about training people to be better at code and they get paid a lot of money to do so. So I've been at all these places that stand up here on stages just like this and tell you how to write your better code. So having worked there, you might wonder like, how much bad code is he, right? I probably just saw a perfect code. And that's not true at all, right? I saw plenty of bad code, some truly truly horrible code while working at all of these places. And that doesn't say that these places are bad or anything, but it does mean a very important fact of the matter is that you can't just hire a bunch of really smart people and feel like you're done. Like there's a number of places out there that will say, you know, we've got this great system where we check everybody and we do code reviews and we go through and we take a look at everybody from a bunch of different angles, from management, from code point of view and then we hire them and they're really good. My second ThoughtWorks project was this monstrous 7-year-old Java app that paid the bills at ThoughtWorks. And you know what? Everybody around there was a ThoughtWorker. There was no way to say, oh it was the client who did it, right? It was totally staffed by and coded by ThoughtWorkers and it was really horrible. It was brutal. I think the code coverage when I first got there, like IU actually turned down the code coverage and it was like 21% and it was bad. It was a lot. At one time it was the largest entity being application in the world, which I'll tell you a little bit. So the thing about writing bad code is pretty much everybody does it. And even if you're real smart, it doesn't necessarily mean you're going to end up with a great code base. So strategies for cutting down on crappy code. By the way, the only valid measurement of code quality is WTS per minute. My favorite thing about this little thing is that even in the good code room, there's a couple of WTS. Like what? Strategies you've all heard about pair programming is a good strategy, right? You get two people, odds are there's one guy sitting there going, you know, maybe we should call that variable X. Something else. Okay, all right. Keeping the maintainer in mind is something that, you know, a lot of people have trouble with because they feel like, hey, I write my own good code and everybody else, like that's their deal. But you're going to write code and then somebody else is going to come along and be in there. And even if you're perfect, and I'm sure you are, you know, you might get a call while you're on vacation and they say, hey, man, we have this big problem with your code. And maybe it's not really a problem. Maybe it was some guy came along and said, well, I just need to have this one extra feature and they didn't really understand your code. You know, there's this idea of sort of where you're at right now. You write for that place because that's where you're at right now. But people tend to forget like dudes are coming on to your project all the time and they may not be great at whatever language you're writing in. Another strategy is to review your old code and see if that hot piece stands up after six months. You know, that is one of my favorite things to do, you know, like you go, I'm in love with this code. This is genius. This is, ah, people are going to love it. And then six months later, you're looking at it and you're like, this is a bunch. This is terrible. I can't stand this. So you can do all these things. Probably a fair amount of guys in this audience actually do do all these things. And what you're going to end up with is a bunch of junk. I've seen these practices applied. I've been in full-on XP teams where everybody's doing everything in every practice and I've still run into bad parts of town. That one controller where everybody's like, you know, I'm going there. That's bad. That's scary. Just leave it alone. Push some logic down into view so you don't have to go into that. A bunch of reasons. One is, you know, a pair is no, you know, it's not a bulletproof defense, you know. I've seen pairs get excited about metaprogramming and they just learned about metaprogramming and I think we're going to use metaprogramming for this and it's going to be great. No, it's not great. The other thing is the late, great George Carlin, you probably realize that he had things to say about software, but he did. And one of his big bits was like, you ever notice when you're on the highway that you're driving along and everybody's going faster than you? You're crazy, man. That guy's going way too fast. Everybody's going slower than you? Those guys are stupid, right? You're driving along. Anybody who's not doing your speed is either crazy or stupid. And it's the same thing with coding, right? Like where you're at right now as a coder tends to be what you think is good for a level of coding, right? It's just something you internalize for yourself, right? So there's been times where I've seen RubyCode when I first got into Ruby and I was like, that's nuts. And then later saw that same RubyCode and went, oh, that's a clever application of X, right? So things to keep in mind is that where you're at right now is not necessarily where everybody else is. Who the hell remembers to look at old code, right? I mean, of course, my favorite looking at old code is the occasional SVN blame, which implicates yourself. That is when you know you've arrived as a coder, right? You're like, this is horrible. Who wrote this? Never mind. The other thing is that every time I ran into a bad pile of code, I would usually go track somebody down and say, why did you write this? And they'd tell me some perfectly reasonable story. Two years ago, the client demanded that we be able to maintain, to talk to the database two different ways so they could deploy two different parts of the apps in two different places, right? Or at separate times. And so they had to have two different ways to access the database. And I was like, cool. So you wrote all that, you wrote to access the database using metaprogramming and Java, okay. So did we ever use that? Like nobody ever deployed that app again, you know, separately. So you could have just taken all that out. Great code plus time often equals trouble. The other thing is that oftentimes you'll have like a neat little piece of like framework code or something that does something hot. And the next guy comes along and goes like, I just add a little bit more to that. And then the other person comes in and puts, I'm going to put a little bit more in there. And before you know it, that method is huge and bad. And there's a lot of things. So no big surprise from the title of this talk. I promote metrics, code metrics as another perspective, right? A way to sort of get outside your own head and outside of the, you know, collective speak of the team and say, you know, what are we really doing and is this good? So I'm going to start off with code coverage. Code coverage. So easy. You're probably already doing it, right? Like somebody on your team probably said, like, hey, I can, you know, get our code working. Cool. And they ran it, you know, maybe they even run it as part of the build. You know, so you have like code coverage stats. So great, huh? How's that working out? You doing anything with that? Like a lot of times metrics, people get a little hot on them and they kind of install them and then they go, oh, look, we have code coverage now. Cool. And then two weeks later, like, nobody ever looks at it again, right? Like, I've been on projects for like, there's code coverage and it's been busted for three months and no one noticed. All right? Like, that's the project I'm on now, right? Like, I was like, hey guys, did you notice the code coverage is working? And they're like, no. Let's fix that. So code coverage inspires a lot of debate. One of them is what's a good coverage number, right? Your tests cover your code. So you've got this thing that's figuring out which lines of code are getting hit by your tests. And so you have code coverage and you have a percent. And you can get to 100% with Ruby. Like, when I was back in the Java days, 85%, much past that was kind of hard. You had to figure out how to get inside all those exceptions. But Ruby, get to 100%. Great. The problem is, is that even though you know 30% is bad, 100% may not be good, right? Like, especially if you have like a team that's kind of pressuring everybody to code covered or maybe even a manager who's saying, we got to cover code. You know, you can write one spec or test. It'll cover like 50 lines of code, right? It might not be any good. I mean, how many times have you been inside a controller test? And it does a bunch of things and then it just asserts success, right? Oh, okay. So it didn't go up. I guess that's coverage of a sort. But not necessarily good. So, I mean, 30% tells you something. 100% may tell you nothing. That's the weird thing about coverage is you may just have, you know, a bunch of really crappy tests that don't actually prevent any bugs. But they hit all those lines. So the question is, is my test any good? I'm going to talk about this more, but a good goal is as many tests as there are paths to a given method, right? So if there's nine ways to get through that method, in theory, that means nine tests. I don't often do that, but it's a good goal, right? It's a good place to try and say, where am I going to? So to sum up my talk, the whole talk now, just to sum up my bit about code coverage, code coverage is just about the worst metric. Just about the worst. It has its uses, right? What I don't like about it is it promotes a false sense of security, is that if you're doing any testing at all, very often you'll like install coverage and you go 93, 92%, great. We're perfect. And then you just sort of wander away, right? And that is not really a good tool then, right? It doesn't told you anything. It just sort of validated you and you felt good in your heart and you moved on. If you have low code coverage, then it tells you where to test. And so that's useful. A lot of people don't know that our code is C0 coverage, right? It's just whether the line got hit. C1 or C2 coverage would be pretty cool. That doesn't exist right now, but you know, that C1 and C2 has to deal with like, you have an if statement and there's a bunch of ands. Maybe you only got through the first one that short circuited, right? Return false, ooh, nothing else like got evaluated. So you hit that line, but you may not have written all that line. And C2 has to do with like different paths to the app, right? If you have big hunks of code, like a big if statement, another if statement, and there's three ways through this if statement, and there's two ways through that, then three times two is six paths, like that's how many paths to the app. But that's, that's tricky, right? Somebody wants to write that. Thanks. I don't know if that's coming anytime soon. So another way to measure metrics on code is complexity measurement. And there's a couple of ways to do this. The first and probably well known in this room, but not super well known in the Ruby community is a FLOG scores. So you can use FLOG to run on your code and it will give you some sort of score. And the biggest complaint I hear about FLOG is they say, hey, you know, that's great. 200. What does that mean? I got a score of 168.5. Is that bad? So I'm going to spend a little bit of time talking about FLOG scores. First of all, FLOG uses what's called an ABC metric, which is assignments, branches, and calls. So assignments, assigning two variables, branches, branching, all right, how many paths, and then calls, like a call off to another method. So here's an example. Pretty straightforward. And here's a FLOG score for it. So in the first one, I'm doing an eval. The next one, I'm doing a branch, very simple branch, then an assignment, then a call. And you can see the FLOG scores over on the right hand side. And the first one, do an eval, gives you six points. The second one, you got a branch, okay, 1.2, and then you have an equal equal, 1.2, and that adds up to 1.7. Yeah, okay, all right. Moving on. All right, so you got assignment, 1.2, and then literal fix. Oh, punishes you for a magic number. Nice, okay. That adds up to, yeah. Oh, and the bottom one works. That's cool. All right, fits. That's a straightforward call. One of the issues with FLOG is that if you go to the FLOG website, first of all, it's scary, right? I don't know if you've been there, but it's like this black and white photo of like a guy, kind of skin ripped off or something. And there's like a picture of some code and then it explains how the numbers come out. And that's a lie. Like if you run FLOG on that code, it doesn't give you that number because he changed it a while ago to use some other algorithm. So it used to be like 1.2 plus 1.2 would be 2.4. It's not anymore. He uses some others. He made a cryptic reference to some sort of distance algorithm, which I'm not really sure what he's doing, but even though FLOG is kind of weird and sort of magical, I really like its relative numbers. Because when you run FLOG on your app, it scores all your methods in the app and it starts right at the top with the most complex one. So you don't really need to know too much about how it works, although it's nice. And you can just say, hey, here's my 10 worse methods. And that's a powerful thing. But to answer your question of what's a good FLOG score, I've run FLOG on a couple of different applications I've worked on. And here's a couple general guidelines. So FLOG score between 0 and 10. Awesome. That method probably doesn't do anything at all, but it's got a really low complexity. 11 to 12. This is possible, right? This is an actual method that maybe does something. And this is good enough, complex, but not bad. 21 to 40. Might need refactoring. 41 to 60. Possible to justify. I've seen things in this range. And the 21 to 60 range is the interesting range for me. I've seen things in there that are horrible and should be refactored immediately. And I've also seen things in there where you're like, nope, it's complex. It's a complex problem space. That's an okay complexity for that particular method. We're in judgment call territory. Once you get much bigger than that, start running the danger zone. Okay. Alarm start going off in your head. You know, like 100. And then this is bad. This is bad. Let me tell you, I've seen these. That's a good time. When you get into the 300s, we got a couple of them on an application that I've been called in to consult on. And, you know, it's been around forever. And guess what? It's in a controller. And yeah, we're going to have to refactor that. And it's going to be complex. It's going to be fun. So here's those are your general guidelines. Vlog is opinionated, which is a good, right? Opinions are good. But documentation is lacking. You go inside the flood source. There's all sorts of interesting methods like bad dog and bleed. And so, yeah. That's, you know, figure it out. That's fun. If I get time to it, I will talk about flame, which is actually a fork of flog, which is an attempt to re-rate flog and put some specs around it. But I might not get to that. Let's see. Relative scores. Excellent. Right. And the really cool thing about flog is that it knows what a badness in Ruby is. Is that if you remember that slide a couple of slides ago where I called out to eval, and then I called out to puts. And the eval gave six points to, and the puts it gave 1.2 points to. Flog knows what's tricky in Ruby. So if you do something like define method, or you do some metaprogramming stuff, or you do a bunch of evals, it says, ooh, tricky stuff, more punishment, more complexity, right? Which is good, because you could write like a pretty short little method and use some really complex stuff and start, you know, open up the module and redefine in something. And that's, you know, that's a part where a new guy in the Ruby is really going to stumble. So the badness in Ruby gets punished by flog appropriately. Now, badness, right, that's a strong word. It could be totally good. You could be writing something really cool. But it is complex. And you should know about it. You should know where the complexity in your code lives. Secure. Secure is a way to measure cyclomatic complexity inside of Ruby. Cyclomatic complexity is a thing that Java developers are really familiar with, but maybe not so much Ruby developers. If you look at this example, this is the code I used before, but I've added a few more examples. I added a branching with some more complex branching, and I also added some metaprogramming down at the bottom just because metaprogramming is cool. And here's a secure readout for this. So secure comes in and measures the cyclomatic complexity of this. Now, cyclomatic complexity can be measured a couple of different ways. Secure takes about the easiest way to measure it. It's, they're measuring just closed paths in your code, right? So if you have ifs, how many ways do you have to get through and get to the end? So if you look at the more branching example, you can get to that line puts B, but then there's two choices there. So you're like, okay, that's two. And then you get that line puts C, but then there's two ways to be there. So that's two more. And then you get to that last puts, but there's another sort of maybe it'll happen, maybe it won't. So you got two more, and I get six. Why seven? Oh, because there's an if and if else maybe none of those things are true. So there's a seventh way to get through that method. All right? Secure does not do the sort of pass through it, right? If you have two big chunks of code and one has five ways to get through it and one has two ways, it doesn't multiply those two together to get 10. It tends to take a more simple way of measuring a cyclomatic complexity is still a useful thing, but you should know that which way it's measuring. And they're totally honest about it if you look at the documentation. Interesting thing here is though, where's the dynamic one? Right? There's a dynamic method down there and it doesn't show up at all. And that's one of the gaping holes right here is that it's not going to pick up dynamically defined methods at all. So be aware. Like on my last project, dynamic methods everywhere. Yes, it was pretty exciting. And I ran secure on it and I'm like, hey, nothing's much above 10 or 12, we're okay, right? No, it was just ignoring all the dynamic stuff. Right? So I was like, oh, darn. So then I ran flood on it. And flood actually does a pretty good job of picking it up, right? So if you'll notice that the dynamic method on the bottom, flood comes along and says, oh, okay, here's this thing defined method branch puts, and it's just sort of in that class. And it measures it up and it just piles it into there. It says like, here's those sort of class secure example, none. And then there's a bunch of complexity score for that stuff in there. So that is pretty useful. Now you've measured your complexity. What do you do? Well, one of the things I did on a couple of projects I've been on is create a hit list. So we just have a list, put up in the dev room, like here's our 10 worst methods, right? And we play dev tasks. And so like you got some time, maybe you should just go look at that method and see what it does. And sometimes the answer is, this is great. This does exactly what it's supposed to do. Other times it's, ooh, this is bad. Wow, this thing's doing 10 different things. Maybe we can break this apart. So I really like the method hit list because you can examine the worst offenders and you can refactor, right? And it's piecemeal and it prioritizes. Because a lot of times we want a project and everybody's like, oh man, the code's so bad. And you got 10 developers in the room and they're all agreeing that the code's bad, but nobody agrees where to start. The cool thing about ranking your methods in order of complexity is, you know where to start. Start with the most complex one. All right. Now for the damn around 11 Stein distance example. So I like real code. Very often at talks, you'll see people say, hey, I'm going to show you like a contrived example, you know? They'll probably even own up to it. They'll say, this is just something I cooked up. This is a real method I found in our source code a couple weeks ago. I did a flawed one on it and I came up with this guy and I said, hey, this is kind of neat. I have no idea what this does. So I'm going to take a look at it. All right. It's a flag score of 155. So that's definitely in the probably should refactor range. And down around 11 Stein is did you mean functionality? So you have a search engine, you have a little box and people type in pizza that they spell it with one Z. So instead of coming back and saying, I have no idea what you're talking about. It'd be cool if you could say, oh, P I Z A is very close to P I Z Z A. Maybe you meant this. So did you mean, right? Google does it really well. We do it okay. So here's demo 11 Stein. This measures the distance between two words. And it's kind of complex. So if you come in here and you scroll down, you see, it's doing a lot of stuff. There's some more over here. Keeps going. And then we return something. So it's like creating a matrix, looping, okay. Got some cases. So various cases, we assign some costs. Then we stick stuff into the matrix. And then if something happens, we stick a different thing in the matrix. Gotcha. Piece of cake. So I said, you know what? Let's take a look at this and see if we can make it a little better. So my first pass at refactoring this, I've now kind of broken it up a little bit. So I said, all right, demo 11 Stein, let's just say that there's this thing called construct starting matrix, right? Because that's just populating a matrix with starting values. Fine. And then we do this loop and there's a part where we calculate the cost. So you take a look at wherever you are in the matrix of these two words and you compute the cost between the two letters. I don't really know how that works quite yet at this point in refactoring, but I know that they're commuting the cost. And then we stick some stuff in to the matrix and we do something called a demoral extension. Let me explain. So here's constructed a starting matrix, pretty much just copy pasted and moved. Here's the cost. Here's the demoral extension. Demoral extension is interesting because it has to do with transposed letters. So say you spell something like, but in Chicago there's this restaurant called Magianos and everybody spells it differently. There's like a million ways to spell Magianos. And if you transpose like a g and an i somewhere, the demoral extension says, hey, you just flipped two letters around. That's not so bad. We're going to give you a discount for that, right? Which is nice. You can find, you know, what's a common human mistake. So you can now say, all right, this thing has a little bit, is a little bit closer in the space to something that transports letters. The interesting thing is that now that I've started pulling this out, I can actually think about it. Like, what are these costs doing? Like, well, this is interesting. Like, they're basically saying if the two letters are the same, then give them a cost of zero. Okay, that makes sense. Like, if you have an R and an R at the same place in those two words, then, okay, they're similar there. Good. And then this does some weird stuff like, okay, got an S and an apostrophe. Well, that's minus two. And this is minus one. That's apostrophe S. Right? So what you're doing is you're saying, like, if I want to get a Geno's East Pizza and I spell it Geno, I want to give you a discount for Geno's. Right? So if I'm suggesting Geno's apostrophe S versus Geno, those are similar. Those are closer. And this one is also doing a similar thing. This has got an O and an apostrophe. O apostrophe. Like, O mallies versus mallies. Which is cool. Now that I've actually pulled this apart into something smaller, I can actually think about this and actually realize what the heck they're trying to do here. The scores are okay. Right? This is 52, 15. Oh, nice. 50, 40. Okay. I did a little bit of the refactoring past pulling out the smaller methods that I did to actually put a word and suggest it into instance variables. I didn't have to pass them around quite so much. I can go farther, though. Right? More. More refactoring. You don't seem that excited. Okay. So here we come in and I'm going to, this is my small reference class. I'm going to pull this apart. So now I just sort of put this in. I construct the starting matrix. Then I just populate the matrix. And then I return some stuff. Construct starting matrix hasn't changed much at all. It's still doing the same stuff. Let's see. Populate matrix. Okay. Loop through this. And then insert Damerrill-Levenstein into matrix. Okay. Okay. Come down here. This guy does the Levenstein cost. And then also the Damerrill extension. Right? So put something in the matrix. And then the Damerrill extension happens if the letters are just transposed. So you get a little discount for that. And then here's the calculate Levenstein cost. Here's an interesting thing. I love of these guys. Right? Same letter just to tell you what that means. Apostrophe S. Oh, apostrophe. So that when you come through here, you're like, oh, here's this encapsulated logic. And it has a nice little name for it, which is cool. Here's the Damerrill extension, our friend. And here's something I labeled transposed letters. Right? So we had this if here that was doing something kind of interesting. I just called it transposed letters to give the next person in a little bit of a clue as to what's happening. It's a couple other factors that happened along the way. I used up to instead of one dot dot three dot each do, just because why not? And there was this weird thing. I don't know if you saw it earlier where like they inserted like some blank spot into the matrix and then populated it. Why not just populate it right away? But and I hope maybe some of you are feeling a little uneasy right now, because that's sort of my point is I think I'm going a little too far here. I've now taken this one method and pulled it apart so much that somebody coming in here may not actually have any idea what's going on. And if I could find my darn mouse, I could go up. It'd be great. Oh, I'm on the screen. Nice. Awesome. Have you ever been in code that's too much refactored? Has had too much refactoring? I have. You come in and you go like, oh, here's what's what's this guy doing? And you say, well, he just calls off to a bunch of other methods. Okay, well, we'll find that other method. That guy doesn't do anything at all. He just calls a bunch of other methods, right? And you do that and you do that. And then by the time you figure out what's going on, you're like, wait, I'm five layers in. I don't remember what was going on up in the top level method. I think that the sweet spot is somewhere between the medium method and the small methods. There's some things I like about the small methods thing like naming something apostrophe S to tell you what's going on. There's also some things I hate about the fact that you have to travel through this whole file just to keep figuring out what's going on. I think if I had to do this over, or if I was going to put this in to the code, I would probably not break it down quite so much. Like one red herring for me is like this populate matrix is just kind of mysterious. What does it do? There's a lot of stuff that doesn't actually refer, you know, like have to do with each other. It seems to break like single responsibility here, right? Like insert, dammer out 11, what are you doing? Two different things here. Why not just do them separately on separate lines instead of creating one method that does these two different things? My personal opinion. And that's an interesting thing about refactoring is that's to taste. That's about you as a team deciding what are good codes to enders. So anyway, you wouldn't of course attempt to do this without having some tests. So here we are. I have a bunch of specs for this guy. And I run them. It would be really cool if that would have popped up over there. And they all don't pass. What's going on? If you look down here, the things that don't work are apostrophe S and O apostrophe. You know why they don't work? Because they don't work. They're not doing anything. Like when I was refactoring this guy, and this is production code that's been lived for a year, I realized that those discounts don't work at all. Like if I just commented them out, I get the exact same numbers. So somebody is very clever and said, I understand Damerall Levinstein. I'm going to give a discount for apostrophe S or O apostrophe. And they wrote it in there, and they had one test to cover this whole thing. And they all did this like some transpose letter thing. And then they were done, right? And then they checked it in and it went out to production. It doesn't work at all. I tracked the guy down and I said, hey, what's going on here? And he was like, you know, I guess it doesn't work. So we sat down and he fixed it, right? We actually just used a G sub to pull out the down apostrophe S. So then it gives it a discounted score, right? It was actually much easier than we were making it. And cool. And this happens all the time. Whenever you find the most complex methods in your app and refactor them, you find bugs. And I've done this on many projects. And I'm already surprised, and I shouldn't be, right? Where do bugs live? Well, you can't see them in the complex areas. So that was my Damerall Levinstein example to the presentation. Okay, refactoring complex methods yields many benefits. So the first very obvious, smaller, easier to understand methods gives somebody a fighting chance when they come in there. You find bugs. This is like, if you need a way to sell this operation to your manager, this is the way to sell it, right? Like, you have bugs, you just don't know it. And we're going to find them using this complexity tool. You can see past the craziness in the code. I don't know about you, but when I see like a method like this big, I just sort of glaze over and I'm like, oh, man, I don't know what that does. It's not magic. It's not that bad. You just got to pull it apart into chunks. And you learn, right? You learn what these methods do as you try to pull them apart. You also can, so when you see into the code, you start thinking about like, hey, one dot dot, wavelength, each, why not one dot up to? Or what's all these i and j's? Like, I still got to go back in there. I think maybe rows and columns. What do you think? Because if you look up in the Wikipedia reference for Levinstein distance, they actually have like a nice little drawing of a matrix and they show you the pass through like, it's rows and columns. Why not call it rows and columns instead of i's and j's? I'm about to start a fight here. Why inject sucks? So when I first got into Ruby, I started working into it and I came across and inject pretty early on in my Ruby life. So I have a little bit of, a little bit of a sore spot with inject, right? And it was, it was like this line of code, right? Like there was some weird thing and there was something I didn't know and then they injected whatever that is. And there was M and O, okay. M, O, some crazy method. M. What's that semicolon? What's that doing? I gotta add no idea, right? I was a Ruby newbie. I didn't have any idea how this worked. And of course, this isn't actually the method, but that's how it read to me, right? It was like, huh, weird stuff, don't know, inject, crazy method. You know, it was just like, it was, it might as well have been magic. So like, you know, I kept like trying to like test it and run things through. I just couldn't figure out what the hell was going on. It was, you know, it was a one liner too. It was just, I don't know. Something to keep in mind is that new developers always join your team, right? People leave, get run over by buses, whatever. You, you get new developers and they're going to have to figure out this code that you write. And sometimes inject is great. Sometimes you're like, that's exactly what I need. It should have been 40 lines, but now it's like a couple of lines great. Other times it's like, ooh, I got, I took it from two lines to one. Good for you. But now it's tricky, right? Now it's a newbie trap. And, you know, the second time I'm going to go back to this is, you know, just because you get it, just because you understand it, doesn't necessarily mean that it's really good. Or that you're going to understand it six months from now, right? Right now you get it. To prove my point, here is an example that has been changed to protect the innocent. But I found this in our code and we had something like this, where we had is something and you pass into stuff and we had to compare a bunch of stuff in some of these two objects, right? And this actually went down much longer, right? It was actually about 10, 10 lines maybe longer. And it had a very high flog score. And so we were like, hey, big flog score, that's a factor. So, okay, cool. So we changed it into this. So, inject true, okay, start out with true, gotcha. Start out with, okay, so it's a true and then x.send b and y.send b, cool. And then, oh, if it ever becomes false, you're doing an and. So they're short circuit, right? So if anything's false, it all becomes false. Woo-hoo, easy, huh? No, not a flog score though. Yeah, hey, numbers, metrics, they're a guideline, right? This was actually a much bigger difference in the wild, right? The flog score was something like 50 and we got it down to like, you know, close to 15 or something. And it was great, except that it was horrible, right? Like, if I look at that top part, I know exactly what that's doing. I can just glance at it and go, oh, you compare a bunch of stuff. Yeah, easy. If I glance at this part, like, I don't know, I gotta think about it. You know, it's a fun little, fun little exercise. So I don't know, you know, I like inject powerful and there's many other things in the movie that are powerful, but every time you add complexity, you're adding, you know, a potential hiding spot for bugs. One thing to do, say, is to explain yourself. So you've decided that you're going to write a framework inside your code, right? You've decided that, hey, we do this thing all the time. So I'm going to create this framework code and it's complex, but damn it, it helps. It's like Rails, right? Rails is complex, but now you can say simple things. That's good. However, you need to explain it, right? It's justifiable if it's framework code or the complex problem space. But I've had examples where not only is it not tested well, but nobody ever talks about it. So, you know, this dude who's real smart went off and wrote, like, well, I'll give you an example, data serialization, right? Inside this project I worked on, we had this data column inside one of the big models. And you look inside it and it's a bunch of yammer. It's a serialized group of stuff, right? And you're like, what the hell is this? And you find out there's still like everything in there. It's like 50 different fields that are being jammed into data, serialized and jammed in there. And I was like, this is so not oh, and it's horrible, and I hate it. And it was just like, I don't want to deal with this. So, like, I would just ignore that stuff, right? I would just say, like, someday we're going to refactor that. That was a mistake of the past. I'm just going to, like, do my own thing. And then, kind of by accident, just by trolling around the code one day, I realized that it was a framework. They had a whole array of, like, you could just declare some method at the top of the model and say, this is a data thing. And then it would just handle everything. And then they actually had a whole framework for inserting it in the CMS in order, in the object, right? It would take care of order. They also made sure that it got indexed by solar automatically, right? There was this whole, cruel framework that I didn't know about. I just ignored it, right? I was just like, oh, what is this doing? So I moved on. And if you're the, you know, the tech lead, the architect, astronaut, whoever, if you're that guy on the team who wrote the cool stuff, it behooves you to explain it to everyone. And not just give up there once and talk about it, although that would help, right? At some sort of dev lunch. But, you know, get around, pair with people. You know, say, hey, have I shown you this? Let me show you how cool this is. First of all, that opens it up to criticism, right? People might say, you know, why didn't you just do this? Or everybody loans it and uses it instead of, like, rewriting it. I mean, I literally have spent days rewriting all the functionality that already existed because I didn't know that this thing existed and it just looked weird. The other thing is test it well, right? You need more complexity? That's fine. Lots of tests. The last bit I want to talk about for as far as metrics is a source control churn. So this is an interesting little thing. Like, it could mean nothing and it could mean a lot. The idea is if you have a file that changes all the time, that may be a code smell, right? You might have a controller that changes all the time, right? Why does that controller have to always change? You might have a model that has to change all the time. It might be doing way too much. That model might be sort of a God object starting to happen. And, you know, it's all about relative scores, right? If you run this and, like, something changes 96 times in the last three months and everything else is at three or four, well, maybe you want to look at that. And maybe it's benign. Maybe it's like marketing always changes the language and this is some configuration file, right? Like, oh, and marketing always changes that file. That's all right. But it could tell you something. So something to think about. Metrics, the downside. First thing I should point out is that numbers do lie, right? You know, they do. They all have an opinion. Somebody had to write this thing, right? Somebody wrote this. Whoever wrote the tool that you're using to analyze it has an opinion and it doesn't necessarily mean that the bad numbers are bad. The bad numbers could be good. That is shown in the flow example, right? You might add something that, like, has a great flow score but it's just, you know, no good. You might have something that has a very low cyclomatic complexity. There's only one path to it. Okay, but it might be huge, right? One very long path. Bad numbers can be good. This is, you know, these are things that provide information to you but you shouldn't religiously follow them. Managers and code metrics. Bad idea. Um, you don't want managers to look at code. I mean, they can look at them. They can even talk about them. They cannot pressure people. It's just bad. It's the old rule of if you want to measure anything and you really want to punish people until it becomes better, that number will become better that your code won't, right? If you really want code coverage, you can get 100% code coverage and if you're walking out with a baseball bat in your hand like, code coverage, we want it. You know, cool. Your developers will write really lousy tests that cover the code. If you get all obsessed about flog scores, they'll make things that have low flog scores except that we pull the part into like 90,000 methods that are all like two lines long and will be, you know, it's basically like sweeping the dirt under the covers, right? You know, you're just like, whew, I don't like that complexity. Let's pull it apart into like 90 methods. Well, I don't know if you've really helped. So gaining the system is constantly a problem, right? If you, if it's not like a team decision and everybody sort of goes, yeah, I agree to this and it becomes sort of an on-high decision, then things can go horribly awry. So what can code metrics do for you? First, helps you prioritize. We know it's bad. Where should we start? Code metrics can tell you where to start. Shine's lights on unknown problems like bugs and hidden complexity. Like a lot of times when I run the flog report, the top four worst methods, you're like, yeah, I knew that. I know that method was bad. But then there'll be like a couple of methods in there and you're like, what? XML, something, something, something parser? Why are we, why don't we write a little XML parser? What? You know, like some crazy method out there. You're like, oh, there's some open source thing we can use instead of this. You know, but the other thing is that, and I just keep returning to this, is that it provides them on a perspective, right? Like what it really does for you is it gets you out of living inside your project and you accept all the things that everybody else in the room accepts and it sort of says like, hey, you know, maybe this is bad. Maybe you should take a look at this. It's another opinion. I wrote a plugin called Metric Foo because I was tired of rewriting the same couple of rake tasks. So really it's just a series of rake tasks that aggregates a couple of things. So it does code coverage with our code, complexity with flog and secure, source control with SVN. I don't use git. It'd be really easy if I did use git for you to submit a patch to me to use git, but I don't. So maybe I will in the future. And if you want to submit some sort of patch to let me work on that, then that'd be great. And then real stats. First of all, because it was easy, right? Just rake stats. And it's also kind of cool to see historic data. So what the goal of this is, is that you integrate this with cruise control, right? And you have it run like once a night, every night at midnight or whatever, whenever you feel like running it. And then you get historical data. So the cool thing is you can look at like, how's my code coverage? Or my complexity? Or my secure, second amount of complexity doing overtime. And so you get like all these sort of outputs for free, right? It's a pretty easy world plug-in to install. And you get reports that tell you a whole bunch of stuff. I also added one thing in there for the flogscorp. You see there's an average flogscorp per method that I thought was kind of a neat thing to know about. Because like flog always tells you like, your total flogscorp is six billion. You go, I don't know. And if you write any more lines of code, that goes up. So it's not the world's greatest number, but your flogscorp per method could actually tell you something. Like if that's going up over time, maybe things are going in a poor way. Metrics are not a fire and forget operation, right? If your code is not getting better every day, then it's getting worse. And this is a fight I have with every manager I've ever had. They're all like, we'll have a tech release sometime in the future. I want to do it every day because the future doesn't come, right? If you're going to have a tech release, and you have to weigh that in your hand versus like, ooh, new features or refactoring code, like it's really, really hard for anybody on the upper level not to choose new features. So what you really want to be doing is using this every day to make your code better moment by moment, day by day. The other advantage is that you start thinking about it. Once you start refactoring bad methods, it puts you in this mindset of like, I don't want to make that mistake again. And you start writing better code because it's influenced by the fact that just yesterday, you had to take this 60 line method apart. I'm Jake Scrubbs. I work at Optiva. That's where Metric Foo is. And then I have a blog that's innovatively titled, Jake Scrubbs. Questions? Yes. Sure. Sure, it's actually on my blog. I published it and so you can... All right, thanks. I want to be associated with bad numbers. Any other questions? So when you worked in the Java world, did you ever use PMD and FindBugs and various other tools like that? You know, when I worked in the Java world, the only thing I knew about at the time was code coverage. So I used Emma a lot. And then? Yeah, Emma to do... Yeah, and that was cool. And then after I got into the Ruby world, I saw a talk by Julyesh Shah about Panopticoad, which is awesome. And that sort of inspired me to do this, right, is to aggregate a bunch of stuff together. Panopticoad is this really cool open source Java project which aggregates a lot of metrics, kind of like MetricFoo does. Well, so PMD and FindBugs use the spec for the language to actually go through, review your code, and find the patterns that will give you a yellow or a red. Like this is a flagrant bug. You're going to have problems, or this could lead to problems. And I was wondering if you know of anything like that. It's on my radar. It may get into MetricFoo at some point. I just haven't gotten around to doing it. But yeah, it's a good idea. Anyone else? This may be a political question, but so on the one hand, you say, you've got to have the commitment to keep doing this. You can't just run the metrics once and then drop it. On the other hand, you say, don't ever let managers run metrics. So how do you manage to pull that off? I mean, how do you, it seems like you're going to have one or the other. So you mean to have a conversation with management about like, hey, these are important, but this is kind of a developer tool, right? This is sort of an inward-facing team developer deal. So it's a value, but it doesn't help if you walk around and say like, flog scores are too much. Like Joey, you wrote a flog score of 156. That's not a helpful thing, right? It's kind of like the no blame environment, right? If you say like, oh, this code is really bad and you start yelling at somebody, it doesn't really help, right? It just makes them cower in fear and learn really bad habits. And that's, you got to have a good manager, right? Like if they don't, you don't think they can handle it. Maybe you don't tell them about it. Anyone else? All right. If we have a moment, I got bonus slides. You got two minutes. Hector was really cool. I didn't have time to talk about it, but it's another thing to vote by Ryan Davis, you run your specs or your tests and it mutates your stuff and it tells you if there's problems. So it changes, like, unless to if and when he runs the tests and says, those tests better fail. And if they don't, you've got a problem, right? So it just inserts random junk into your code and then he runs the test and says, those better fail, right? And if they don't, you don't probably as good a test as you think you do. It's not something I run like on a nightly basis, but it is kind of a cool learning tool to see if you have good tests for a complex plate piece. The other thing is Flame is a fork of FLOG with specs written around it. There was a really cool talk at Ruby Hoedown by Rick Bradley, which I watched on Confreaks, which is my new favorite site. And you can just, you know, check that out and he goes through and looks at FLOG, takes it apart, makes it more understandable, and yeah, it's on that fancy new git somewhere. Anyway, well, thanks again.