 How's everybody doing? Nice crowd. You guys look good. We've got people packed in the back. Can you guys do me a favor? I think this is the biggest crowd that's ever turned out for a talk of mine. So will you do me a favor and wave hi to my mom? You guys are great sports. Thank you so much. So my name is Ben Ornstein. I work, what's that? Oh yeah, absolutely. After the talk. So my name is Ben Ornstein. I work at Thoughtbot in Boston. And this talk is about refactoring. Do we have any fans of refactoring in the audience? Do we have any Rubyists in the audience? Do we have anyone in the audience who's never raised their hand before? Interesting. So just a quick little bit of administration I want to get out of the way. This talk is not a lecture from the clouds. This is not me telling you the one true way to do things. This is not a lecture at all. This is pairing. I would now like to pair a program with all of you. So please consider this an informal dialogue. Now this is partly because I want you to understand things. The purpose of this talk is not for me to reach the end. It's to teach you things. But also, I want you to be able to correct my mistakes when I make mistakes in live coding. So I'm going to need those backups, six or 700 pairs of eyes, or single eyes. So let's get started. Let's look at some code. Who likes looking at code? Here's some code. Take a second and read this. Use both of your eyes. What's that? Do you want to try it? Here, let's have a vote. Better or worse? Can we have them removed, please, security? We have a heckler. You're a bad pair, sir. Getting the gist of this, we take a collection of orders. We take a start date and an end date. And we're curious what the total sales were during the date range we pass in. Now, I have specs for this code. I run them like this. They're going to go by really fast because I'm not loading rails. Yeah. So I'll be running these tests continuously as I'm doing these refactorings, much as you always do 100% of the time when you're refactoring, right? Excellent. That's the first rule of refactoring. Don't refactor code that doesn't have tests. All right. So looking at this code, this is roughly how it would have written this report about 18 months ago or so. I probably would look at this, call it good enough, and commit it, or actually, I'd probably check it in back in some version days, and call it a day. But now I look at this code and I think there are some things that could be better. So let's start with one. Check out line 12. I have this temp variable called orders within range. I'm assigning it the results of some calculation. Now, the first thing I would do, something I've been doing a lot lately, is pulling out temp variables into query methods. So I have a macro recorded that does this. Don't freak out, but it's going to happen fast. Here's the before. Here's the after. I've pulled that temp into a private method with the same name, and I'm just referencing it here. And now why am I doing this? Well, first of all, notice, despite the weird wrapping that's going on, what's actually happened here is I've gone from one method with two lines to two methods with one line. Now, I'm not going to tell you that that is always 100% of the time a good idea, but it's usually the right direction. Usually feel good. Usually feels good. The rule of methods is that they should just do one thing. And shorter methods are more likely to be doing one thing. So that's nice. The methods are shorter, but also there's another benefit we picked up here, which is that we can reuse it. So when orders within range is a temp variable like this, it's locked up inside this method. When it's like this, it's not. That calculation is now available to other methods in this class. And I think it's actually a little bit more likely that I'm going to reuse this rather than duplicate it when I pull it out like that. Finally, there's a third benefit, and this actually might even be the most important one. When I pull out that calculation into a private method, it's less likely that you'll read it. So when you look at code like this, because we're programmers and we like to read code, we see orders within range equals, and then we read what goes into that value. And we figure it out, and we parse it, and we run it in our heads. When it looks like this, you're more likely to say, oh, that's a private method, okay, and move on. And you're just gonna take my word for it that orders within range returns the orders that are within the range. So I've given you a hint right here. The hint is, this is an implementation detail. It's not important. It's a lower level of abstraction that we're not interested in. There's another benefit pulling that out into a query method. So let's take a look at where we are now. This code's getting better, but it's not great. So one place, another place I start to look for refactoring these days, isn't, what about our test? Good call, yeah, thank you, still green. Man, this is why you have pairs, because you forget stuff. Okay, so we're still green, thank goodness. So another place I look for refactoring these days is in these semi-complicated bodies of selects like this. See how you've got this and and in here? That is a good hint to me that that could be refactored, that we could give a name for this. And also, notice what we're doing with order. We're asking order questions about itself. So we're saying, hey order, what's your place stat? When were you placed at? And I'm gonna do some calculations. And if you match these calculations, I'm gonna select you. Now, I don't love this. This feels a little bit like feature envy. A feature envy is where one class seems really interested in a different object, and it's a smell. It says maybe that method that seems really interested in that other object should actually be moved. You should actually move it to that class. So what if rather than poking it at order and pulling out one of its attributes, what if we just had a method on order that would answer the question that we want to have answered? So here's what this might look like. We could just say, hey order, were you placed between the start date and the end date? What's that? No macro for this one. So by the way, I had so many people ask me in recordings how I wrote that macro that extracted the private thing. That's just like a one-off macro. It's not generalizable. I wrote it just for this talk, just so you guys wouldn't have to sit there and watch me fiddle with this. But sadly, it is not a general macro yet. How about using a range? How about using a range? That's a perfectly good question and we're totally gonna use a range object in a few steps. So this guy, this man is from five minutes in the future. So what happens now when we run our test? Oh, they bomb because as we guess, order does not have a place between method. So let's write one. Place between takes a start date and an end date. And now we have to say, is our place that after the start date and is our place that before the end date? Did I get those things right? Let's see, I did. Okay, so now I think this code is looking a little better. Let's move this down so you can see it. Can I do that? Nope, silly Ruby. So things are looking better. I now like that the logic for determining if an order is placed between two dates is an order. It's a thing that we have order deal with. Rather than pulling out pieces of order and making decisions on its behalf, we're sending order a message and be like, hey, you worry about this. You figure out this, you contain this collection. That's sort of a nice, or you contain this calculation. And that's a nice direction to be heading in in object-oriented programming. I like that this calculation is closer to where the data is. But now if you look, we've introduced another smell. So take a look at all the places where we have the pair of start date and end date. We pass it in the initializer, we pass it down to order, and we use it in this method. So this is something that I believe Martin Fowler calls a data clump. A data clump is just one or two or more parameters that you see together all the time, particularly in parameter lists and argument lists. And a great test to see if you have a data clump is to try taking away one of the elements. So if we had a start date and an end date and we wanna know something between them and I took away the start date, it doesn't really make sense anymore. Those things are actually linked. They're basically one concept. Maybe it's a range, who knows. But it'd be nice to take this implicit concept, which is start date and end date all of us show up together, and make it an explicit concept. That's something I find myself thinking about a lot these days. What is something that's implicit in this code that it could make more explicit? Because the more explicit you make it, the more easy it is to understand. The less likely it is that you're gonna have to explain it to somebody else, especially yourself in three months. So what would this look like? Well, when you have a data clump, the thing to do is give it a class and stick those things together. So let's take a look at what that would look like. I'd rather then have, let's see, how we wanna do this. We'll do this in small steps. So let's start by making the date range right here. So I'm gonna say range. I'm gonna create a new class called date range. And I pass the start date and the end date into it. And then I'm gonna feed it into here into our order place between. Yes, it's because I, well, yes. So a normal range will work. This is for illustrative purposes. I'll talk about using a plain range in a second. But yeah, I think there's a slight, I think there's a slight benefit to calling it date range instead of just a plain range. Makes it a little more obvious, but I think at the end of the day, I might replace this with a range, but we'll talk about this in a sec. So I wanna create a new date range. We have an initial as constant, which we would expect. Here's our new date range. And I'm just gonna make it take a start date and an end date. See how we're doing now. So we have the wrong number of arguments now for place between right in here. So let's make this take a date range. And now we're gonna need to call start date and end date on the date range. Back to green. So let's go one step further. We have this date range. Rather than build it in order, I'd rather pass it into order. I'd rather invert control and inject this dependency instead. So what does that look like? Let's open up our spec for a second. So I'm gonna actually feed in the start date and end date from the test. I'm gonna come in here, pass in that range into orders report. This blows up because we're now passing the wrong number of arguments to orders report. So let's find that. Date range here, date range, and now down here. Rather than building the date range that's already built. And we can just reference the range from here. Oh, thank you. That's what I get for using different names. All right, back to green. Everybody follow what we just did right there? New class. It holds the start date and end date. It's just packaging them up. So is this a win? No. No, yes. We have no as we have yeses. I think it's a win. Yes. Good. So why is it a win? Well, first of all, we've reduced coupling here. So what's coupling? Coupling is the degree to which components in a system rely on each other. And we're interested in coupling as programmers because when two things are extremely coupled, it becomes very hard to change one without affecting the other. Whereas if two things are completely decoupled, you can change one all day and never affect the other. So in general, in our programs, lower coupling is better because we want to make it easy to change things. That's a really good metric for code equality. How easy is this to change? So what kind of coupling existed before? Well, there's one kind of coupling called parameter coupling. Let's look at an example of that. So in our top method, we pass in an object called failure. Don't worry about that, it's not coming from anywhere. And we pass it into print to console. So print to console then calls a method on failure. It calls two sentence on failure. Now the thing to notice here is print to console and notify user of failure are coupled to each other. And they're coupled because notify user of failure has to build the right failure object to pass into the other method. If I create an object, if failure here does not respond to two sentence, this method will blow up. So in effect, the fact that this method calls two sentence on its parameter has leaked over to this other method. They are coupled to each other. One depends on the other and less coupling is better in general. So parameter coupling is one kind of coupling. The interesting thing about this is if you have a method that takes no arguments, it has no parameter coupling. And that actually means that a method that takes no arguments is superior to a method that takes one argument. And those of you that are familiar with induction will probably guess that a method that takes one argument is better than a method that takes two arguments. So it's actually worth your time often to slim down your parameter lists. It tends to make your code easier to understand, but also it reduces coupling, it reduces parameter coupling. Not always a huge win, but it's usually a good idea. So now we've taken our orders report from three arguments to two by putting this together in a date range. Also, we've now got a really handy place to hang new behavior. So notice that order place between is answering the question, hey, is some date between two other dates? This seems like the kind of thing that I'm gonna wanna reuse. I might wanna say, hey, was this coupon issued between two dates? Hey, was this gift certificate redeemed between two dates? I could see myself wanting to answer this place between question in a lot of places. And we happen to have a great new place to hang that behavior now, which is on date range. Corey Haines has a cute name for this which is called, he calls this behavior magnets, which I think is really nice. This date range class starts off very simple, but it's a behavior magnet. So what can we do? Now, how can we use that? So in order, in place between, rather than doing this logic ourselves, let's just ask the date range. Do you include my place that? And then, oh, that's include is our question. Date, and we'll say, is date after the start date? And is it before the end date? We're still green. So I'm really liking this now. This class, this report, this situation, I'm really liking it. We have, I like that when order wants to know if something's placed between, it asks the date range. And all that order really knows in this method is that the thing that you should pass in is the place that attribute. I like that order knows how to answer that question. I like that the behavior or the calculation for determining if things are included in the date range lives in its own class called date range. That seems like a good place to have it in there. But let's do a little quick refactoring in here. So someone asked if we could just use a range here. Yeah, we could use a range. If I made this, this could sub-classroom range, it could compose a range. I'm just gonna build the range in here on the fly. So let's do start date, end date, that include date. And this should work the same way. And it does. One other thing, by the way, that was pointed out in a talk, and this is why it's fun to give talks to a room full of programmers that are pairing with you. The issue, there's one little slight performance thing here that we can do slightly better. So if you ask a range, if it includes something, the first thing the range does is it instantiates everything inside it into a collection, and then it searches through that collection and sees if that thing it's looking for is inside there. But since this is a range, we really only need to instantiate the things on the end and then do some math and figure out if the thing we're looking for is inside it. And there actually is a method for this. It's called cover. So just a tiny little performance when there maybe makes this a tiny bit clearer of what we're looking to do. A couple tiny little things to clean this class up and then we're gonna be done. We'll move on to another example. For my public methods in particular, I really like them to read super nicely. I like this for all things, but particularly for these public methods that people are gonna tend to read, I want them to read very well. So the one thing I'm not liking to hear about this is this big, meaty pile of junk over here. So let's create a method called total sales that takes a collection of orders. And let's move this bad boy down here. Orders and we'll do this. See if we're still green and we are. And inject, this could be a little bit simpler, right? We can just do this for feeling clever. We can also get rid of the zero kind of. Why can't we get rid of the zero? Exactly, the collection might be empty. Right, but the total sales of no orders is zero. It's not nil or empty array or whatever would come back from that. Right? Nil is not a number, this man is correct. I wish I had a t-shirt to throw at you. Or something heavier, whatever. So one thing to point out here, I told you that parameter coupling is not great. And that methods that take no arguments are better than ones that take one. And I actually introduced some parameter coupling here. I'm passing in these orders into this private method. And that feels a little smelly. It feels a little questionable. I think I've increased the readability. I would argue that the method called total sales within date range that reads total sales of orders within range is pretty darn readable. But I've definitely increased this parameter coupling here. And so what was pointed out to me is that this probably means that orders, the collection itself wants to have these methods. And that way, I can just ask orders.total sales with no parameter and orders.orderswithinrange with no parameters, no parameter coupling. I think it looks like these methods might want to move under the collection of orders. However, that is going to be left as an exercise to the readers. We're going to move on. But first, we've been working hard. So we deserve the one slide in my screen. Oh, that didn't quite work. Yeah, this is the closest thing I have to a slide in my talk. Let's all just take a cleansing breath as the cat dances by. All right, how's everybody doing? Feeling good? Feeling excited? Awesome. All right, let's move on to another example. All right, let's pull up another example and we get my specs going first. I'm going to run them. They're green. Okay, here's some more code for you to read. Take a second and read it. One more method down here. Contact is, looks like this. Okay. So what is not so great about this class? Well, here's a problem. So here's the thing. This represents a job site. Now every job site has a location. Jobs always happen somewhere. Every job site does not necessarily have a contact. We don't always know who we should get in touch with for the job. So because of this, sometimes contact is going to be nil. And because contact could be nil, we have to handle that. So we need to check for its presence and provide a default. Same thing for phone. The same thing for email contact. This man has seen the future. So what are we doing here? We've co-opted nil. We're asking nil to stand in for a contact that doesn't really exist. Because that's what we pass in here. If we don't assign at contact, it's going to be nil. And so we're saying, hey nil, you just mean no contact. And because we've co-opted nil and we're making it stand for something that it really doesn't want to stand for, we have to check for it all over the place. So how do we fix this? Well, let's make something that stands in for having no contact. So let's create a nil contact. And so why don't we do that? Where's the best place to do this guy? Line eight? So if we do it in line eight, we're going to break a bunch of things. We're going to have to refactor three methods at once and we'll be red the whole time. Is there a place we can do it where it's smaller? We can make a smaller change and get green faster. Hmm? Line six? I don't think, what about, what if we did this? Network? So this is going to blow up because nil contact doesn't exist. Let's go to find nil contact. And we need to give it, let's not take too many steps. So nil contact now exists, but it doesn't have a method called name. So let's give it a name. And we saw before that the default should be no name. Back to green. This is something our CTO Joe Ferris pointed out to me. So the first, I did it the way that someone suggested earlier. The first thing I did was say, all right, let's make this nil contact up here. But then you're doing way more work while you are not green. You're red for longer. And it's actually worth thinking about doing refactoring in smaller steps. It's easier to keep it in your head. It's easier to understand. Hi. It's okay. This is Mr. Nil contact everybody. Okay, so let's replace another instance. Let's do this here. Dot new dot phone. This blows up because phone is not defined. We'll define it back to green, baby steps. Anybody feeling stressed? Of course you're not, because we're taking tiny steps. Refactoring is easy. We could do this all day. And here, well, I don't really see a good way of doing this here. So now I'm actually gonna swap it in up in the initializer. Nil contact dot new. This is saying now we don't have the deliver personalized email method on null contact, which is true. This takes an email. And notice I can just leave this method body blank because when there's no contact, we just don't do anything. So I'm just gonna define that empty method on null contact. Now we're still green, but we've got this null contact line up here. Now we get to do something which is every programmer's favorite job, which is what? No. Absolutely. There's no such thing as an audience of programmers that does not know the answer to that question. I'm giving this talk a handful of times that always comes back instantly. Everyone knows what we're gonna say. Okay, so let's do this. Oops. Oh God. Whoops. Does anybody ever have their Vim stop undoing? I'm not the only one. Undo does not work right now. If I change this and hit undo, it was like no, go to hell. Let's quit Vim and come back real quick. I need undo. Okay, contact dot name. Run the tests. Oh, geez. Yeah, we need it. No worries. Don't panic. Null spec. Okay, that's the error we want. Don't panic, guys. Woo, all right. Good. Now more deleting code. And this. What's this? My tests say I'm okay. All right, so what just happened? Well, we stopped co-opting nil. We made a very simple little class. Does anyone have trouble understanding the nil contact class? No, of course not. It's insanely simple. It's insanely straightforward. And in exchange for that very simple class with very simple methods, I got to improve the heck out of this. We deleted 10 lines of code. We removed a bunch of conditionals, which is great because conditionals must die. And also we removed the obscuration, the obfuscation of those methods. Checking for contact all the time made it harder to see what those methods really did. I think this is a lot clearer in exchange for a very small, very easy to understand class. Now, here's a question for you. How many people have in their Rails app right now a line that reads something like, if current user, yada, yada, yada? Yeah, put your hands up, you liars. Okay. Can you see how this might map to that? Rather than having current user return nil, which then you're co-opting to stand in for not having someone signed in, you could return a site visitor object or something along those lines and have a real class stand for that concept instead and clean up those conditionals. No one caveat. People often ask, how do you make this work in the view? Well, it's more of a pain. So this is sort of a, we're sort of talking about following tell, don't ask. We don't wanna ask contact if it exists. We'd rather just send it a message. Tell, don't ask gets a little bit hairy in the view because a lot of times you're doing a lot of asking in the view, right? A view basically exists to show your representation of something. So I'm less stringent about following tell, don't ask when I'm in the view. But outside that I'd much rather just send messages to objects and not have to worry and check for nil. All right, let's move along to one more example and then where I'm gonna summarize and we're gonna talk about some other stuff and it's gonna be awesome. All right, so take a look at some more code. So this is a user class and the user class happens to know how to charge for a subscription. It looks up a brain tree ID based on some semantics and then charges. Brain tree by the way, if you don't know is a payment processor. There's a gem that handles that wraps up the payment processing. Here's a refund that uses slightly different semantics to look up the transaction ID and then refunds it. Now, how is this code? Well, it's okay. So most programs are familiar with a key ID, a key idea for easing change and that idea is depend upon abstractions, right? Like no one is shoving raw bytes out of socket, right? You're using a library that handles it for you. Most people aren't writing a ton of raw SQL using something that generates SQL for you. You're depending upon abstractions so that if implementation details change, you don't need to worry about it and that makes it easier for your code to change. They're shielded from changes at the lower levels. Your code doesn't have to care as much. So most programs are familiar with that idea but what they don't always realize is that this idea is sort of fractal. It zooms out and it zooms in. So just like I'm not gonna be pumping bytes out down a socket, I also don't want to depend on concrete details in my business objects. So when we have this, yes, I'm using a Braintree gem here and this Braintree gem is an abstraction over making raw HTTP calls to Braintree but it doesn't mean that these classes are depending upon abstraction. For instance, let's say I change our payment gateway. Now we wanna switch to Stripe. It's the new hotness, it's great, we're gonna try that. What happens? Well, I have to go change my user model. That feels weird, right? I also have to go change my refund model. I wanna change this one thing and I have to change it in many places. One name for this is shotgun surgery. Cute, right? Another thing is this is divergent change. There are two reasons for my user class to change. One is that the business logic surrounding my user changes and the other is that my payment gateway changes. And divergent change is a sign that you have multiple concerns inside a class. So I basically let the Braintree details leak into user. So here's one way you could fix this. I would create a payment gateway object. It takes the Braintree gateway and I've moved all those methods from user and from refund into here. Now this class knows the semantics of looking at Braintree things and refunding Braintree things and creating customers. And user just knows how to call up the gateway and tell it what it wants done. It passes itself in, it doesn't know about the details. Now it's easy to change gems, right? If I wanna use a different Braintree gem, I don't have to change user at all. If I wanted to switch payment providers, which happens, I've done it, I don't have to change user, I don't have to change refund. All those changes happen in one place, the payment gateway class, which seems to make a lot of sense. That's where I would expect to go to make those changes, not user. Also, let's say I wanted to have different, I wanted to do different things when Braintree's down. Let's say if Braintree's down, I can't just stop accepting orders. I wanna do something like take on some risk by just saying, yeah, that's fine, we'll take your order and we'll charge you for it later. I can do that here. I can swap in a gateway that behaves differently and the code that calls the payment gateway never knows. I'm not gonna let that concern leak out across my system. Everything else is depending upon that abstraction and so I'm able to create a nice and encapsulated thing that handles all of that. Finally, it's nice and easy to mock this. In my previous example, if I wanna test this method, I have to mock out methods on Braintree's gem. And that feels kinda gross. I don't really wanna do that. It's possible they'll change the API around on me. I don't really like reaching into other people's code and messing with it, but I'm totally, totally happy to mock my own methods and mock out that payment gateway. That feels fine. I'm totally okay with that. This is by the way, is an example of the adapter pattern. I'm creating an adapter for the rest of my code to use that sits between the next level, the lower level details. Okay, so we've done some good coverage of different refactoring ideas, different tools you can use, but the question, one question is when do you refactor? When are these things worth doing? The first time is all the time. And what I mean by all the time is I mean after every change you make, the cycle is red, green, refactor. Do your refactoring right after the test goes green. And then also, when you check in, get a diff of your changes and look at them. Give yourself a mini code review. See if there's anything you've introduced, if there's any smells, if there's any obvious problems, and fix those early. Always be refactoring a little bit and you don't need to go on these missions. If you've ever had to convince a management person of like look, we need the next week to refactor this thing so that we can do the other thing. That is not a fun conversation to have. No one likes to have that conversation, no one likes to hear that conversation. If you're refactoring continuously, you make it less likely that you're gonna get yourself in that state. So that's the first time to refactor. Another time to refactor is when you have God objects. So what's a God object? Well, a God object is something, an object in a system that everything seems to rely on. Everything somehow seems to connect to this thing and call methods on it. There's in Rails apps, there are very commonly two God objects. The first one is what? Yes, user. And the other one is whatever that application is about. So if it's an e-commerce application, it's order. If it's a to-do list application, it's to-do. Those are two likely candidates. So when you are dealing with God objects, it's a great idea to be extra aggressive with your refactoring and make sure you don't make them worse. When you have to go in there and touch user, make user better, don't make it longer. By the way, here's a great way to get a feel for what might be your God objects. So I'm in an app model's directory of an anonymous application that I will not name for you. I'm gonna get the word count, the line count of every class in this directory and then I'm gonna sort it. Can you guess what kind of application this is? It's an e-commerce application. So this is not a great tool. Pure line count is not a perfect measure of complexity, right? If you have a class that has a very low line count but every line is insanely complicated, that's not great, right? But it gives you a rough idea. What's a better way? Well, there's a couple things. There's some tools like FLOG and FLAY and things like that. I've been playing around with this lately, code climate. It gives you metrics on your Ruby code and it can even tell you every time you push if you've made your code better or if you've made it worse. That's a nice place to look to give you an idea. This is codeclimate.com. Give you an idea if your code's getting better or worse and those metrics are better. They're better than a pure line count. They're considering the complexity, the cyclomatic complexity of code. Do you have a lot of conditionals? Do you have confusing things? Do you have duplication? It's giving you a better picture of that. So, okay. Got objects all the time. Got objects. And where else? High-churn files. So if you write a horrendous piece of garbage and you commit it and no one ever has to change it again, if a tree falls in the forest, right? If you never need to read it and you never need to change it and no one ever looks at it, well, why would you refactor that? That's a waste of your time. However, if you have a file that changes all the time and it's that same pile of crap, that's definitely worth refactoring because you're in there all the time. And the fact that it's changing often is probably a hint that you don't have it quite right and it probably warrants refactoring. Finally, I just got vimmed. Finally, a great place to look for refactoring is where you find bugs. Because what does a bug really mean? A bug means you didn't understand the code you wrote. And doing a good set of refactoring can make that code clear. The thing about bugs is that they love company. If you find a bug right here, they're probably a bug right here. You didn't understand the code and you can make it clear by doing some smart refactoring. So before we wrap up, I wanna show you a couple of book recommendations. Number one, I think this is just about the best general book about writing better code there is. It's by Bob Martin, Uncle Bob. This is excellent. This is another one. Growing object-oriented software guided by tests. I wrote this book off because the title sounded introductory. And in a way it kind of is, but it's also not. It's a great book. It does an amazing job of describing certain things about TDD and object-oriented programming in ways that I had never seen before and suddenly made me see the light in a light coming down from the heavens kind of way. Really good writing, totally recommended. Finally, if you're feeling the mood to learn, if this has gotten you fired up, learn.thoughtbot.com, we get a lot of screencasts, we got ebooks, we got blog posts, we got a lot of stuff going on here. There's a refactoring screencast that you might wanna check out. By the way, we have a discount code for you, RubyConf 2012, all lowercase. That's good for the conference and then we're gonna turn it off on you. And finally, anybody here listen to the podcast by any chance? Awesome, cool. So we have a podcast. It's often very technical. Sometimes it's about its entrepreneurs and a lot of times it gets technical. We talk about object-oriented stuff and we talk about refactoring and a lot of people have found it useful, so you might too. I think that's all I have for you. So let's take some questions, yeah. Another book recommendation is Michael Feather's working effectively with Legacy Code. The title is also in the speech as well. It's a fantastic book on how we factor. Awesome, that's not a question. There's always one. So the book was working effectively with Legacy Code by Michael Feathers, yeah. Yeah, so you said you talked about the objects, but could you give us any ideas about suggestions for what to do with God Objects? Yes, extract behavior out of them. Yeah, so God Objects will typically have multiple concerns, multiple responsibilities. So find a responsibility, find a package of methods that seem to go with each other and represent one responsibility and extract a class with that. That's my general tool. I think it's a, also, are you familiar with solid? Are you familiar with the solid principles? It's a really good idea to follow solid principles in classes that are God Objects. Yeah. For those of us not familiar with solid principles? Yes. What are they? Let me Google that for you. Yeah, so it's SOLIDs, five principles put together by Bob Martin. Bob Martin. One of them is a single responsibility principle and there are some other ones. They're basically guidelines. I remember the others, I just don't wanna waste your time. I do, we just talked about this, no seriously. No, but take a look, those are worth looking at. And actually, I think I'm pretty sure he covers a lot of them in clean code. So it's worth taking a look for that. Yes. All right. Hi. So I was looking in your order class where you're passing in the customer and the first example you've passed in a contact name that might be NIL. Yes. So basically the only way that would happen is if someone passed in a NIL argument. All right, you're forcing them, but you're forcing them to pass something in in first place because you're not sending a default for it. Right. But even if you made a default parameter, someone might still pass in a NIL object. Yes. But it would still be better to reset it in the default, right? It would be better to, so that they don't have to pass a NIL object to get a NIL. Are you suggesting having a default of a NIL contact for a contact? Yeah, that's a totally reasonable idea. Someone still might pass a NIL, well, they're jerks. No, seriously. Well, what do you want me to do when they pass a NIL? Like raise? Raise, you're a jerk. Don't pass a NIL. Yeah, this guy likes that. Yeah, but yeah, I sometimes will put things like a NIL object as a default for a parameter, but that's sort of a sneaky conditional, right? That's really saying if parameter, then parameter else NIL contact. And like that just sort of adds a little bit of overhead from me. So I'll usually do that inside the initializer instead of the argument list. That's it. It depends on where you're feeling confident or like about your code. It's where do you want to fix it? Sure. Yep. Yeah. So at what point do you start adding tests for an object like NIL? Oh, good question. So the question was, at what point do I start adding tests for an object like the NIL contact? And it depends. So sometimes those little, so that's sort of a little service class almost in that particular class. I'm using it only in one place, right? It's only involved in the whatever that class was. So for classes like that, especially if I make them private, I won't write tests for it. I'll test them implicitly or indirectly through the interface of the class that does use it. As soon as I pull that out and put it somewhere that other people are gonna use it, I'll write tests for that. Yes. It sort of follows on that would you then put it if it's a private one in the same file and then you start using it as a separate file? Yes. The question was where does it go basically? So if it's private, I keep it in the same file. If it becomes an honest class in its own, a first class class, then I would move it out into its own file. Yep. Yeah. Yeah. Would I go a step further and inject my payment gateway into user? Probably. Probably. It would depend. It would depend enough that there seemed to be a good reason to do that. Wouldn't it make user more of an object? Shouldn't it be separate functionality? Wouldn't that make user more of a God object? No, I don't think so because it's already using the payment gateway. So he's asking, I could just inject that payment gateway instead. And yeah, that's totally reasonable. I could invert control on user and just pass that in there. Yep. Yeah, John. Yeah, he's saying if different users could have different payment gateways then I would definitely inject it. But, and that's definitely one argument for dependency injection though. It's also nice for testing, right? For throwing a stub in there or some sort of mock object instead of an actual payment gateway. Yep. Can you talk briefly about the decorator pattern and you kind of miss it? And also, what's the use for that? So this guy's holding me to the talk description that I wrote six months ago. No, I'm not gonna talk about the decorator pattern but I will talk to you afterwards if you want about it. And then a gem. Some people like Draper, we haven't found a great use for it yet. When we wanna do a decorator, we generally do it, we just sort of roll our own on the fly. What's that? Death is my decorator. I like that. That's a good t-shirt. Yeah. Actually, we just recorded a podcast about, like in the DCI context that we were thinking. So we recorded a podcast with Jim Gaye, the author of Clean Ruby. And we talked about that at length so I encourage you to check out that podcast when it comes out. I can't duplicate. I gotta stay dry. That was a lot. That was a slow clap. Yeah, okay, slow clap, that's okay. I did it, yes. Why don't you take the path that you did when in the example of not walking, we had a lot of size, keeping the basic steps. Yeah. Braking, as I said. Whereas a lot of us in the audience see, whoa, we're gonna pull that code or we're gonna reach that final limitation. Yep. There's a whole path we could take. Yeah. We're gonna have to choose the one we did. So the rough question was, why did I prioritize taking small steps when we did that null customer refactoring? And so I sent a copy of a recording in my talk to our CTO Joe Ferris who was right there. And one of his points of feedback, he actually pointed out two times in my talk, he said you can refactor in smaller steps here. And I thought it was really interesting that he had picked up on that because that's something that I don't always think about. But it's actually a really good habit I think is taking those little steps. You want your tests to be as green as often as possible because whenever they're green you know you're good, you know things are working. And the longer you go in a cycle when things are red, the more likely it is you can kind of go off the track. Right? Is that a fair description, Joe, of the advantage? Yep, Joe says yes. Thumbs up. Proved by Joe. So that's a great question because it was something that I didn't think about a lot. I'm more cognizant of it now and that's something that I have it that I want to improve on. Yeah. They were singing about using null objects in context of a lot of two associations. Yeah, so he's asking if you can use null objects in the context of belong to associations. As long as you are in a recent-ish version of Rails I believe you can get away with this in the same way. I think if you're back in the two-something days it wouldn't work. But I think after three-two-ish, anybody know for sure, you can call super and then handle the using a null object there. So yeah, give it a shot. I think it works. Anybody know it doesn't work? All right, must work. Last chance, anybody else? All right, thank you very much.