Lately I’ve been making a lot of mistakes while refactoring large projects. You know – the kind of mistakes that leave you scratching your head for an hour or two wondering why your test just won’t turn green. With help from my mentor, I’ve come up with a few tips that decrease the amount of time I spend scratching my head and make refactoring a bit smoother.
Add before you delete
When you add or update methods, add the new code before you delete your old code. I often write test and methods before realizing that my method should be two or three methods instead of just one. I use to cut and paste to a new method or delete that section and rewrite it in a new method. I would be often be left with broken tests for a while and have a lot of trouble figuring out where I went wrong.
This problem can usually be prevented by creating tests for a new method, and then writing that method before you even delete the old code. Make sure you’re tests are passing before you link to your new method and delete the old code. Once everything looks good you can make the switch from the old method to the new method.
Here’s a good example:
example.rb
class ExampleOfBadMethod def long_method(animal) if animal == "golden retriever" || selection == "poodle" || selection == "pug" "Bark! elsif animal == "kitten" || selection == "siamese" || selection == "cat" "Meow!" else puts "What is that?!" end end end #rspec tests below describe "Example of bad method" do it "responds bark if animal is a dog" do expect(long_method("poodle").to eq("Bark!") end it "responds meow if animal is a cat" do expect(long_method("cat").to eq("Meow!") end end
Now write your new code before deleting old.
class ExampleOfBadMethod def long_method(animal) if animal == "golden retriever" || selection == "poodle" || selection == "pug" "Bark! elsif animal == "kitten" || selection == "siamese" || selection == "cat" "Meow!" else puts "What is that?!" end end def is_dog?(animal) if animal == "golden retriever" || selection == "poodle" || selection == "pug" return true else return false end end def is_cat?(animal) if animal == "kitten" || selection == "siamese" || selection == "cat" return true else return false end end end #rspec tests below describe "Example of bad method" do it "responds bark if animal is a dog" do expect(long_method("poodle")).to eq("Bark!") end it "responds meow if animal is a cat" do expect(long_method("cat")).to eq("Meow!") end it "responds bark if animal is a dog" do expect(is_dog?("poodle")).to eq(true) expect(is_dog?("cat")).to eq(false) end it "responds meow if animal is a cat" do expect(is_cat?("cat")).to eq(true) expect(is_cat?("poodle")).to eq(false) end end
Now delete the old code.
class ExampleOfGoodMethod def long_method(animal) if is_dog?(animal) "Bark! elsif is_cat?(animal) "Meow!" else puts "What is that?!" end end def is_dog?(animal) if animal == "golden retriever" || selection == "poodle" || selection == "pug" return true else return false end end def is_cat?(animal) if animal == "kitten" || selection == "siamese" || selection == "cat" return true else return false end end end #rspec tests below describe "Example of good method" do it "responds bark if animal is a dog" do expect(long_method("poodle")).to eq("Bark!") end it "responds meow if animal is a cat" do expect(long_method("cat")).to eq("Meow!") end it "responds bark if animal is a dog" do expect(is_dog?("poodle")).to eq(true) expect(is_dog?("cat")).to eq(false) end it "responds meow if animal is a cat" do expect(is_cat?("cat")).to eq(true) expect(is_cat?("poodle")).to eq(false) end end
There you go! Cleaned up code and nothing broke.
Google (No really, google more)
Googling is an important skill for every developer. It’s impossible to remember every method and pattern for every language you use. As much as I understand this, I recently realized that I’m not googling enough. I’m still pretty new to the world of programming and working on a lot of small projects and challenges. I always make a valiant effort to figure these out on my own and try my best not to look for or copy code from the internet. So because of that, I don’t Google enough. I’ve been missing out on really helpful methods, knowledge and tips from StackOverflow, and blog posts that discuss strategies and patterns.
Plan ahead
In projects where I have a runner class or other high-level classes, I don’t always want to create them first. But it still helps to have an idea of how they will run your program. It might help to write down the order of your runner, i.e., the list of steps you’ll take to run your program. Then just try to knock them off one-by-one in order or start with the easier classes or methods first to get them out of the way. Then you might want to go ahead and create your high-level classes which end up piecing everything together.
It also helps to draw pictures of your class structures or your data structures to visualize what you’re going to build.