Software Development Practices

Summarized using AI

So You Want to Start Refactoring?

Jillian Foley • April 21, 2015 • Atlanta, GA

In the talk 'So You Want to Start Refactoring?' presented by Jillian Foley at RailsConf 2015, the focus is on demystifying the concept of refactoring for new programmers and outlining effective strategies for improving existing code without changing its external behavior. Foley begins by discussing her personal experience with legacy code—code previously written by others—and emphasizes the common apprehension surrounding the term 'refactoring'.

The key points discussed include:

- Definition of Refactoring: Foley cites Martin Fowler's definition that describes refactoring as a disciplined technique for restructuring existing code without altering its external behavior.
- Importance of Refactoring: The reasons highlighted include:

- Maintainability: Well-organized code is easier to understand and modify.

- Scalability: Structured code allows for better performance and easier onboarding for new developers.

- Flexibility: Clean code facilitates quick adjustments and pivots.
- General Cleanup: Similar to personal habits, code also requires periodic cleaning to enhance productivity.
- Identifying the Need for Refactoring: Signs that indicate refactoring is necessary include overwhelming bugs, decreased performance, and new team members' confusion over existing code.
- Preparing for Refactoring: Foley emphasizes the importance of preparation, such as increasing test coverage, reviewing functionality, and understanding code style before starting a refactor. For instance, she suggests not to mix changing tests while modifying application code.
- Approach to Refactoring: The steps include annotating the code, starting with small changes, renaming variables for clarity, simplifying complex conditionals, and determining where code logically belongs.
- Case Study: Foley gives a brief case study demonstrating her refactoring of a signup controller, detailing how she simplified variables, clarified code structure, and moved certain validations to the front-end.

The talk concludes with the notion that refactoring does not have to be intimidating. By viewing it as a process for making code cleaner and safer for future developers, programmers can gain a better understanding and increase their skills. Foley invites viewers to consider refactoring their past projects as a way to reinforce their learning and improve their coding practices.

So You Want to Start Refactoring?
Jillian Foley • April 21, 2015 • Atlanta, GA

By, Jillian Foley
New programmers often react with dread when the word "refactoring" starts getting thrown around at standup. Maybe you've seen fellow Rubyists struggle with old code, or a colleague spend days on one module only to end up with exactly zero changes to functionality. What exactly is refactoring, and why would anyone want to do it? What are some tips for approaching a refactor, both generally and in Rails?

Help us caption & translate this video!

http://amara.org/v/G71X/

RailsConf 2015

00:00:12.040 Welcome to 'So You Want to Start Refactoring?' My name is Jillian Foley, and I'm going to be talking about refactoring.
00:00:18.480 So, just sort of an opening question: who here has spent a significant amount of time working in code written by other people? Okay, so most of you. Is there anyone in here who has spent most of their time working only in their own code?
00:00:31.400 Okay, a few of you. A little bit about me: I'm one of those people that has pretty much only worked in other people's code. I'm currently a software engineer at a company in D.C. called Contactually.
00:00:44.399 I started coding on the job. I was sort of thrown into a programming internship by my dad without knowing how to code. I feel bad for that boss. So, basically, this means that I've learned how to deal with other people's code before I've ever really learned how to write my own code from scratch.
00:00:55.359 This means that I've done a lot of refactoring before I even knew that word. I actually didn't really know what 'refactoring' meant. It seemed kind of scary until maybe two years ago. I've been coding in Rails since technically 2007.
00:01:08.200 So, I've pretty much only worked in legacy code. And I'm sure that since most of you have worked in legacy code, you know what I mean. But just to clarify: by legacy code, I mean code written by other people, code that's been around for a while, it's had multiple versions, and it's been touched by a lot of people.
00:01:21.439 You know, code develops cruft over time, so this is pretty crufty code we're talking about. One little more bona fide about myself for this talk is that one time my boss gave me a box of Pop-Tarts with my face on it as sort of an award for refactoring an internal tool.
00:01:36.119 So, if you refactor, you too can get a box of real Pop-Tarts with your face on them. Those are real Pop-Tarts, as you can see, cinnamon roll flavored. So, what is refactoring? This is the million-dollar question. Probably some of you know what it is, but probably some of you are at this talk because you're like, 'I don't know what that means.' Here's a good definition I found; this is on Martin Fowler's website for his refactoring books. Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior.
00:02:06.240 I like this definition; I think it's pretty precise without being too technical. But just to break it down a little bit, the idea is to not have any change to your users. Your app stays the same. They don't even know anything's happening, but you have an improvement for your developers; so, you, your teammates, and other people that work in your code see the code getting better, even though your users necessarily don't know that anything's happening.
00:02:38.560 One other sort of quote that I think I like for this idea of refactoring is from a sort of notable architect known as Le Corbusier. I don't actually know what that means. It's: 'We must refuse to afford even the slightest concession to the mess we are in now.' So, in his architecture world, he was talking about improving the future and building spaces that improve the future. But in our sense, this is sort of like if our code is a mess. It doesn't need to stay a mess; it doesn't need to be a mess forever, and we can fix it.
00:03:09.360 So, why would you want to refactor? Obviously, I've mentioned one big reason: your code is a mess, and you want to fix it. But you'll see this question a lot, especially if you work on a bigger team, a corporate team, or a team that has a lot of external deadlines. You'll get this question a lot from people like product managers and CEOs: 'Refactoring? We don't have time for that! We need new features right now. We need new features all the time! We don't have time to waste on cleaning up our old code messes.'
00:03:56.480 Sometimes, it can be hard to get management to prioritize code practices. So, I'm going to try to talk a little bit about why you'd want to refactor and what you can tell these people to even get them to agree to do it before we get into how exactly you do it. So, why would you want to refactor? I see there's four big reasons here.
00:04:21.560 We have maintainability. Those of you that have worked in other people's code know that it's always easier to work in other people's code when it's well organized. When you know what you're looking for, it's much easier to go find a bug that you've seen before if it's code that you know where to find stuff.
00:04:40.199 It's easier to add new features to code that's well organized. You're like, 'Oh, this fits in exactly this slot.' Scalability: there's two things here. First is the usual scalability. Again, it's sort of easier to make your code performant when you know where things are, when you know you're not accidentally making the same database call on 47 different files.
00:04:54.160 But it's also that refactoring helps make your team scalable. This is sort of the beginner track. Some of you might be beginners; some of you work with beginners. It's much easier for new people, whether they're brand new to coding or just new to your team. It's much easier to onboard them when you don't have to sit and explain your code for three weeks when they start.
00:05:22.720 I see some people nodding. You know what I'm talking about. Flexibility: this goes along with maintainability. It's easier to do those pivots that people in startups like to talk about so much. If you can see the code that you want to change, you don’t have to go hunt it down before you start working on it.
00:05:55.680 Spring cleaning: this is a good one if you're talking to someone who just doesn't see the value in it. If it's important to spring clean your apartment, clean out your closet, or take your car in for an oil change, you spend way more time in your code than you spend in your car, so why not put the same investment into your code that you would put into your car?
00:06:28.640 Now that you've convinced your management that you think it's a good idea to refactor, they agree with you, and they think it's a good time to refactor, how do you know that it's actually time right now to refactor?
00:06:39.440 So, who in here has come across code that they couldn't understand or that seemed poorly organized? Yeah, most of you. If you're a beginner, sometimes you come across this code and you think, 'Oh, I’m just a dummy.' If anyone was in the talk before this, that's one of those things. You come across something and you're like, 'Oh, I’m just stupid! I'm too afraid to ask. I don't want to make a mistake.'
00:06:58.240 A lot of times, the code really is pretty hard to understand; it's not just you. It actually is the code. And so I think this is something that's important to refactoring, is to trust your gut and to know that if you think something looks weird, chances are it might be a little bit weird. So, if you think in your soul, if you really feel that it's time for a refactor, you might be right.
00:07:36.720 But here are some warning signs: if you're overwhelmed by bugs, especially bugs coming from a single part of the code; if you're seeing decreased performance, this can come from a lot of factors, but refactoring might help you pinpoint what some of those things are before they get too bad.
00:08:21.200 If again a new person comes on your team and looks at this code and says, 'Guys, what on Earth is this?' you might not have someone who's that bold, but sometimes you do, who comes in and is like, 'This code is crazy! What have you guys been doing this whole time?' These are all good signs that you should go into your code and take a look at it; it might be time to do some spring cleaning.
00:08:42.560 In the Game of Thrones world, winter is coming, and it's time to make sure that you get your harvest in before winter comes for God knows how long. But sometimes you don't catch these things on time, and then you end up like this guy. So, you don't want to end up like this guy. These are signs that you've waited too long; you need to refactor right now. You probably should have done it already.
00:09:03.279 Tests are increasingly hard to write. I like to point this one out because I think in a lot of cases tests are sort of the canary in the coal mine. If writing tests for a bug fix or writing tests for new features is increasingly hard because you're relying on lots of outside assumptions or it requires a lot of extra pieces to set up and to stub out before you can even test something, maybe it's time to think about how you've structured that piece of code.
00:09:27.520 I'd like to point out here that tests can also be refactored. Just because your tests are hard to write, doesn't necessarily mean that your code needs refactoring; it might mean that your tests need refactoring.
00:09:48.480 I've also seen code that's so poorly organized it's blocking new progress. It just takes too long to write anything in this piece of code, so you can't add new features there. That's a good sign that you should have gone back and refactored, and now is the time to do it, so that you can, like I said, be more flexible, be more scalable, and things like that.
00:10:12.760 If your code is crashing, that's probably a good sign that something is wrong. Especially if it's coming from the same piece of code over and over again, production crashing might mean that, yeah, you have a bug, but you might have a bug that's colonized and has spread, and the whole code just kind of needs to be cleaned out of all these bugs.
00:10:28.000 So, the meat of the presentation here: how do you do it? There are lots of different approaches to refactoring. This is sort of, I'm just going to walk through how I generally approach it. There's a lot of different ways. If you've never done it before, this will hopefully give you some ideas of how to approach this concept. If you have done it before, maybe this will give you some new ideas.
00:10:55.680 So, the first thing I like to do is prepare. I have this phrase up here: Mise en place, which is a French phrase that people use in cooking. That's basically like if you're going to start cooking, the best thing to do is to get all of your supplies set up before you even start. So, measure out all of your ingredients, put them in little bowls, get all of your tools out, lay it all out. That way, when you're stirring sauce on the stove and there's tomato sauce splattering everywhere and you realize you need the salt that's all the way across the kitchen, you don't have to run across and have everything burned and everything is terrible.
00:11:33.680 So, before you start a refactor, you want to do that kind of thing to make sure that you're not scrambling in the middle, wasting stuff, burning your kitchen, or going up in flames. Some things that are important in this process are beefing up your test coverage. In the Rails community, we have a lot of cool tools to make sure that you have good test coverage. This is the time to get out those coverage reports. This is the time to look at those code quality metrics that I'm sure a lot of you use.
00:12:02.320 Even if you're a backend developer, if you're tackling a refactor, you need to look at your front-end tests and make sure that they cover everything or cover as much as you can. This is a good time to review the functionality of what you're trying to refactor. Sometimes, especially if you're a backend developer, you might not know exactly how the front-end works, how people interact with it on a day-to-day basis. This is just good practice as a developer generally, but this is a good time to do it.
00:12:29.760 It's a good idea to sit down with the product manager or the customer support person, or even the senior developer that's been there longer than you, and make sure that you know exactly how this code is supposed to work and exactly what it's supposed to do. It's hard to refactor and keep that end goal the same if you don't know what it is.
00:12:55.440 You want to make sure that you have a really solid foundation in what you're refactoring. And then, make sure you brush up on code style. Code style is really important to a lot of people to make sure that, especially if you're working on a team, everyone is sort of on the same page. This is a good chance to make sure that you know what your team expects and what sort of trends you're moving towards.
00:13:22.760 If your team is really trying to move logic out of the controller into the model, you don't want to do a giant refactor that puts all of the logic back in the controller. It might be cleaner code, but you know it's not really where your team is going. Those are the kinds of things to keep in mind while you're doing this.
00:13:50.560 I want to point out at this point: if you're taking a refactor of application code, you don't want to change tests while you're refactoring. This is a pretty important point that was not fully explained to me on one of the big refactors that I was asked to do because I was a noob and I didn't think to ask.
00:14:06.720 If you're keeping your production functionality the same for your end users, your tests are going to be your safety net to make sure that you're actually keeping that you're not breaking anything in your refactor, you're not making anything totally different. So, if you change your tests midway, you don't have that safety net anymore; your safety net has been moved and shifted, and maybe now it's all the way over there, and you're still dangling from a tree over here.
00:14:56.560 So, that's a good way to get your test coverage up to snuff: do it beforehand, make a separate commit, get that pushed through. Now you have better test coverage, which is great just generally, even if you never do a refactor; but that makes sure that you have that safety net during your refactor.
00:15:22.799 And then, like I mentioned before, you can always refactor tests. If you are refactoring your tests, the flip side is true. Don't go changing your application code while you're changing your tests. You want the same test to pass at the beginning that passes at the end.
00:15:41.800 And if you've changed them, you can't be 100% certain you didn't screw anything up; hopefully you didn't, but you never know. So, once you have all this preparation done, you're all set; you have your test coverage done, that's all merged in and everything looks great.
00:16:10.240 The next thing I like to do is go through the code that you're targeting and annotate it. So, this is basically reading through and commenting on anything that stands out to you as weird or bad.
00:16:27.440 This is, you know, some people like comments; some people don't. These comments will go away once you're done, but this is a good way to go through and highlight to yourself: this is the stuff that looks weird to me, this is the stuff that looks bad, this is what I want to fix. One thing that I like to do sometimes—this doesn't always work—is consider copying outside code that gets used in the code that you're looking at.
00:16:57.920 So, if you're in a controller and your code is relying pretty heavily on this validation that's done in your model, you might want to consider copying that validation over. If you're having trouble remembering what it does or you're having trouble seeing how all the pieces fit together, you can put it in a comment.
00:17:09.240 You can take it out when you're done; you don't have to worry about making your code undo DRY or whatever, but it sort of helps to see everything in front of you all at once. It might even help you figure out that maybe that logic you just copied over belonged in the controller the whole time.
00:17:27.199 This doesn't always apply, but I think that's an important thing: copying isn't always bad. You don't want to keep it necessarily, but you can always copy temporarily. And then, the last part is to rename variables and methods. Some of these will get renamed permanently; we'll talk about this more later, but some of these are just for clarity.
00:18:03.120 For example, say you're going through some controller code and you keep running into this method called clear_params. You're like, 'What is clear_params?' Maybe that's not a good name. At the end of the refactor, you decide it really should be called clean_params or strong_params or something standard.
00:18:43.679 So, you're going through the code that you're refactoring, and you rename all the instances of clear_params to fix_params by removing all that crazy stuff. So every time you see it, you know exactly what's happening. You don't have to remember, 'Oh wait, what was clear_params again?' You know it's fixing the params by removing all the crazy stuff.
00:19:09.840 That's obviously too long of a name to keep in your code. You don't want to keep that there forever, but it's a good chance to give yourself an explanation inline that doesn't interrupt the flow of you understanding the code while you're working on it.
00:19:26.800 Understanding is the key; that's what you're trying to get at the end of a refactor. So, making sure that you're understanding what you're reading, even if it doesn't stay that way forever, allows you to sort of experiment with crazy weird stuff; you can always change it.
00:19:44.200 What are kinds of things you want to look for when you're annotating? Some people call them code smells; I like to call them code messes, like your dog makes little messes—you still love it; it's still lovable.
00:20:04.160 What looks redundant? We don't like redundancy, me in the Ruby world or in any coding world, I hope. What is too complex? Your code should be clear and non-repetitive. What parts of the code took more than one to two reads to understand? Again, this is a time where you should trust your gut; don’t just assume that because it took you four reads to understand what was happening, that you're just a dummy and didn't understand it.
00:20:45.920 It probably was poorly written. And even if at the end you decide that nothing about that can be changed and it really just is a complicated concept, maybe it needs more inline commenting; that's something to know for yourself.
00:21:09.760 Do you see any methods that look bloated? We don't need to go all the way crazy down and be like Unix and have only one action per method, but you want to get closer to that. You don't want to have a method that's 20 gazillion lines long, because what would you even name that? What would it do?
00:21:29.560 Mark those kinds of things down. And then does any of it violate your code standards? This is pretty simple; there are lots of tools that can help you find these things, but this is a good time to mark those things down.
00:21:52.320 So, once you've pinpointed all these things, you have nice annotated code; it's all marked up. How do you do it? You go through and clean up your code. This is the part that's really the meat of actually doing the refactor and this is the part that might seem the most overwhelming if you've never done that before. So, I like to recommend people don’t start at the top; usually, if you're reading through a file, once you've annotated it, you know where all the problems are.
00:22:31.840 You don’t need to start at the top again. Start at the easiest thing for you to do. If that's all you've done, you've still made an improvement. So, if you have a bunch of instances, for example, of someone using single-letter variable names, those are pretty easy, really low-hanging fruit. You can go through and clean all of those up; make that a commit. If that's all you do, that's a great refactor; you've just made the code more easily understood for other people who come after you.
00:23:06.760 Tackle those small things first before working your way up to more complex things. Focus on one method at a time; make sure that nothing is repeated. Those are pretty easy things to do: just pull stuff out, make new methods, smaller methods, those kinds of things.
00:23:34.240 I mentioned names before; this is a good time to make sure that your method names make sense. Maybe you don’t want to leave 'fix crazy params' by removing all the ugly stuff, but maybe you want to rename it to 'clean params' or 'strong params', something that is more indicative of what it’s actually doing. Fix those style issues I mentioned; that's a pretty easy one. Most of us can handle that, even if you don't necessarily agree with hash rockets versus not hash rockets.
00:24:10.240 As we get down the list here, things get slightly more complicated. Simplifying conditionals is one of those things that is really important to making code readable and is one of the harder things for people to do. If you have to sit down and draw some truth tables or do Venn diagrams, like, stop it, take the time and do it. One thing I like to do with crazy looking conditionals is to break it down.
00:24:45.040 If you have a bunch of ANDs and ORs or nested things, break each one down so that you have nothing nested and no ANDs. Maybe you're repeating all of your crazy conditionals, but it helps you get a handle on what actually is happening. And then if you need to, you can build it back up and combine things as necessary. But it might help you see, 'Oh, I didn’t actually need to check this four different times because in effect I've checked it just this one time.' So, now you've gotten rid of half of them.
00:25:20.960 And then the probably the most complex thing here is making sure that your code lives where it truly belongs. Some of this is team style preferences, like I mentioned. Some of it, for example: my team is moving a lot of our front-end logic into JavaScript, which we all know how DHH feels about that. And if that's where you're going, maybe that's what you need to do.
00:25:51.120 But if there's not an overwhelming preference for these kinds of things, then this is your time to sit and think critically about: does this actually make sense here? Is this controller code actually important for a specific controller action, or is it integral to my model? Does this code truly need to be moved into my model?
00:26:25.920 Is this something—this really complex looking method—is this something that really needs to live in my model, or is this something that I can pull out and put into a JavaScript so that I don’t have to wait for my model to respond for this crazy looking thing?
00:27:07.440 These are important things to think about. This is the kind of thing too where if you get to this point, you're like, 'I don’t feel like this really belongs here, but I'm not sure where it belongs.' That's a good chance to pull in someone else from your team. If your team does pair programming, that's a good chance to sit down and say, 'I feel weird about this method being in here. Something seems off to me; where do you think it could go?' Or sit down with someone and maybe try it over here. See how it goes; see how many tests fail.
00:27:43.840 Once you move it to the model, see how many tests fail when you move it to your backbone model. Sort of feel it out; bounce ideas off someone else to help you get a sense of where something actually truly should live.
00:27:56.560 Now that we've gone through some ideas on how to actually approach doing it, I have a very brief case study. Obviously, showing a whole refactor on a little slide in a 30-minute talk is not going to be very practical. So what I did was I pulled out a small snippet of an actual refactor that I did recently, and I'm just going to walk through it to sort of illustrate the method that I was just talking about in some of the concepts.
00:28:28.960 But this will mostly just look like I'm cleaning up some code, which, I mean, to be fair, that's what refactoring actually is. None of this should be too mind-blowing, which is also good because it's really not that mind-blowing. This code was part of our signup controller, and we were trying to refactor a very small bit of it, and it snowballed into a very big refactor. This was from the new method of someone signing up for a free trial.
00:29:15.680 So, you can kind of just look at the shape of this code, and you can kind of tell it looks bad. The first line is really long; does it really need to be that long? Do we really need to have like four methods chained together? You can see we have a bunch of nested stuff with like 'unless' and then 'if' and then 'if not', which is basically unless, and we could see some single-letter variables, which are always horrible.
00:29:51.360 So, we go through and annotate it. Here are my annotations I made for this particular bit of code. You can see, 'Why is this so long?' Another bit is: 'Why are we having param?' Like, what are param signup objects? Object-oriented programming doesn't really tell me: what is a signup? We didn't have a signup model in this particular project, so I was like, 'I don't really know what that is.'
00:30:27.440 This takes me a lot of—like that was one of those I had to go pull extra code in my comments to see what exactly this was passing to me. We got some nested conditionals, single-letter variables, we're assigning this 'u' variable twice. What are we doing that for? So this is all pretty ugly. When I was addressing these comments, how did I go through here?
00:30:56.240 So, from easiest to hardest, in this particular case the easiest thing to do is to fix the names. We took these single-letter variables and made them actually useful. So these 'u's are actually users, and the 'a's are actually accounts. We don’t need the 's' and the 'a's; that's unnecessary.
00:31:13.679 We simplified these conditionals, so this is when I broke it all out, and then built it back together. So we don’t have 'unless' and 'else' and double nested things. And then probably the biggest thing that we did here was I went back to this param signup.
00:31:38.560 The first thing was to take this like triple chained method at the top here that does some crazy thing with the email and only downcases the first 100 letters. I still don't know why that was there, but what we did was we changed it to it was just a front-end validation, which is really where this should have belonged the whole time.
00:32:05.680 Making sure that someone is actually giving us a valid email address and that we don't need to do anything to it by the time it gets to us. And then the very last thing was going back to the form that was generating these signup params, realizing that what it was actually doing was creating a user object and just renaming it params_user.
00:32:32.160 As a Rails community, params_user is something that you have a built-in understanding of what that means. Params for a user? That's cool! Params for signup? I didn’t know what that was, but params for user? I'm like, 'Oh, okay! Here's some user params; maybe we'll use strong params on it, maybe we won't, but this is going to create me a user object, which is what in fact this was doing.'
00:33:13.220 So, renaming that, what was coming out of that form made it sort of more Rails-y and easier for other people to understand. So, once I got through refactoring this, this is what it looked like. You can see that I also added in some explanatory comments, which for things that I thought were confusing for someone new to read.
00:33:30.080 But that we couldn't necessarily change, like we were checking this demo account. I didn’t really know what that was or why we were doing this, so I put in some comments once I found out.
00:33:55.920 You can see we renamed the params here; we made the variables useful variables instead of 'A' and 'E' and 'U'. And then the conditionals were broken down here so that nothing is nested and nothing is using a 'if not' or 'unless', which is always a little bit harder to understand.
00:34:06.480 In this case, you can see you might have noticed that we're checking if an existing user exists twice. Some people might look at that and be like, 'Oh hey, that's not DRY!' In this particular case, we decided that that check wasn’t too expensive and that the readability of this part of the code trumped whatever we might lose by not repeating that.
00:34:28.080 We thought that the double-nested conditional was a little too complicated and that repeating this one time once was fine for our team. So that's something else: you don't always necessarily need to adhere to style super-duper hard if readability is your goal.
00:34:56.400 So here's some other tips now that we've gone through this brief case study: test frequently. This is why you have those tests. This is why you went through and added those tests. Make sure you're also testing manually if this is something on the front end or something that you can test manually.
00:35:13.179 This is why you had to understand what the functionality was; your tests don’t cover everything. Even if you magically have 100% test coverage—if you say you do, I don't believe you.
00:35:34.920 Again, don't change your tests while refactoring! Please don’t do it; I did it, learn from my mistakes. It goes poorly.
00:35:49.920 Commit frequently; once you have a green, once you make a change—say you changed all those variable names to something that made more sense—run your test just to make sure that you didn’t mess anything up. Once they're green, commit, push it, open up a PR, and say, 'Look what I did!' Then you already have a refactor.
00:36:07.360 So, make sure you're committing frequently that way; if you do break your tests, it's easier to go back to the last thing that was green.
00:36:28.160 I mentioned earlier tools like RuboCop or Reek can help you find places in your code that are breaking style, find places in your code that you may have missed that are code smelly. To give you something to start on, those kinds of things can help you; you might be like, 'Oh, this method is way too long.' You're like, 'Oh, I hadn't even noticed!'
00:37:05.360 Sometimes, consider pausing after a logical group of changes. So after your tests pass—in the example I was giving of changing the variable names—after that passes, maybe you decide you want to deploy it. It only took a day; you did it, got reviewed, it got merged, deploy! Cool; refactor deployed; awesome, done!
00:37:40.440 One thing with this last bit though, is when you're planning what to group together or what to deploy together, sometimes you run into two different ways to do it. Sometimes you plan; sometimes they don’t work. On one hand, you have this lovely turtle who is trying to slowly and steadily creep his way through—doing little bits at a time and incrementally changing stuff.
00:38:05.040 Sometimes this is great; sometimes this is what you need to do. Sometimes the structure of your management on your team is such that it's easier to just grab little bits of time here and there instead of trying to get a whole sprint prioritized for a refactor.
00:38:25.760 On the other hand, sometimes you work on a team where making everyone have a heads down, like, 'We're going to work for an entire solid week and everyone's going to refactor!' Maybe that's more useful for your team and that will get all the changes done at once. That's great; kudos for you if you work on that team!
00:38:47.920 And just to go back to the slow and steady for a second: sometimes it's easier to, even if you don't have maybe express permission, like, 'I'm going to refactor!' If you're touching a piece of code, sometimes people like to talk about the idea of leaving code better than when you found it. This is a good way to do that.
00:39:17.680 Not only can you go in and fix a bug—it's a one-line fix—you make sure your test passed, and then you're like, 'Well, while I'm in here, this looks a little weird.' That's a good chance to just say you have a 10-line method, and you fixed a bug on one of the lines; it took you two minutes. You can totally spend another hour maybe fixing up that method a little bit, and then it's nicer for the next person that comes along.
00:39:44.960 It didn’t take you that long; you didn’t have to fight for a refactor or anything like that. Those are really easy things that even brand new beginners can do. But one point—also, I sort of mentioned this with our example—is that sometimes if you try to start a small change, it can really easily snowball. You pull on one string and the whole thing comes apart. It can really easily snowball into refactoring a whole bunch of stuff.
00:40:18.840 So keep that in mind; if that starts happening and you're not prepared for it, it's fine. Commit the stuff or stash your changes and go back; maybe wait till you have time to pair with someone more senior than you if it's something that's overwhelming. That can always happen. It doesn’t mean you're doing it wrong; it just means that code is complicated. Code is complicated; there's no way around it.
00:40:54.960 A few other things to remember: refactoring is not scary. We do it all the time. We don't even always call it refactoring; it's a good way to learn new design patterns. The refactor that actually got me that Pop-Tart box was a refactor of a DSL. I’d never worked in DSL; I didn't know that DSL stood for Domain Specific Language.
00:41:14.560 I had no idea what good practices were for that. So it was a good chance for me to go and read about these things, read about how the code was structured, read about all the ways in which the code I was taking was breaking all of those rules and how to not break the rules in the end product.
00:41:44.840 And I wouldn't have learned any of that stuff if I had just continued working in the code the way that it was. It's a good way to learn your codebase, not only because you're doing the things at the beginning that we talked about, like fixing your test and making sure you understand the functionality, but this is the sort of stuff that you can really sit down with maybe the person that wrote that code, maybe that person’s not around, or it's a whole bunch of people.
00:42:17.680 But the person who most recently did a lot in that code or the most senior dev on your team and say, 'Can you walk me through this? I'm having some trouble understanding what's going on in here.' And that's a good way to sort of get a refactor started and also to understand really, really deeply what is happening in this code.
00:42:47.920 What exactly is happening in here? Why is it structured the way that it's structured? And how can we make it better? Again, tests can be refactored too; if you're a tester, if you're not a tester and you see your test and you're like, 'I don’t understand what these tests are testing', that's a good chance to go back and refactor your test; even if it's just the descriptions of your RSpec.
00:43:09.520 Those are all important things. These are all refactors, by the way. Some of these things sound really small, but like I said, refactoring is not scary. And then a good thing to do, especially for beginners, is to go back and refactor your old projects.
00:43:34.960 The first things that you coded, this might sound really scary because probably the first things that you coded, now that you’ve been coding for a while, you'd probably read them and think, 'Oh, why did I do that?'
00:44:02.120 But this is a great example of: you're probably going to read some other people's code who have been coding for twice as long as you have and go, 'Why did you do that?' So this is a good practice. If you can do it to yourself, you can do it to other people.
00:44:20.840 Now that you've learned all these things about refactoring, you can go forth and refactor. Any questions?
Explore all talks recorded at RailsConf 2015
+122