You know what stinks? Trash. You know what stinks less? Well organized trash in tidy bins.
Code smells can also arise from long methods in poorly organized classes. Have you ever walked-up to a waste receptacle and been totally confused by which bin to throw your item in? Just like how you don’t want to stand in front of the trash bin and read complicated instructions about how to throw away your sandwich container, you don’t want to create a lot of overly complicated logic piled into one class when you are programming because this is hard to communicate to other people who may read your code. It it is also more likely to break in the future.
You want your classes to only do one thing and you want your methods short and sweet. We are going to practice refactoring a confusing ‘Recycle’ class to demonstrate. Here’s a hypothetical program for throwing a piece of trash into the Big Belly Solar trash bins:
The instructions on the trash bins are probably correct, they are just confusing. Let’s improve the design of how we communicate this logic.
In their book, Refactoring, Jay Fields, Shane Harvie, Martin Fowler, and Kent Beck have several suggestions for tackling bloated classes and long, complicated methods. The example above purposely contains a case statement. Truth be told, I didn’t realize that case statements were a code smell until reading this book. In OO programming, case statements are are one of the most obvious code smells. There are several strategies for simplifying case and if/else statements to make their functionality more clear and the code less susceptible to breaking in the future.
The first step that should be taken when refactoring is to be a solid set of tests for the bit of code that will be tackled.
One solution could include Polymorphism. This essentially means that the new code would allow you to avoid writing an explicit conditional when you have objects whose behavior varies depending on their types. In Ruby this can be achieved by implementing the same method signature on multiple objects and calling these methods polymorphically.
Steps: 1. If the conditional statement is one part of larger method, take apart the conditional statement and use Extract Method.
If necessary use Move Method to place the conditional at the appropriate place in the object structure.
Pick on of the polymorphic objects. Create a method on the polymorphic object that will override the conditional statement method. Copy the body of that leg of the conditional statement in the polymorphic method and adjust to fit.
Test.
Remove the copied leg of the conditional statement
Test.
Repeat with each leg of the conditional statement until all legs are turned into polymorphic methods.
*Long Methods are BAD. Refactor them. In summary, the least stinky and longest lived object programs are those with short methods. Just like how you hate decoding instructions on recycling bins, since the early days of programming people have realized that the longer a procedure is, the more difficult it is to understand and more likely it is to break. The net effect is that you should be much more aggressive about decomposing methods.
Ninety-nine percent of the time, all you have to do to shorten a method is Extract Method. Find parts of the method that seem to go nicely together and make a new method.
Polymorphism can also bring with it many advantages when the same set of conditions appear in many places in the program. If you want to add a new type, you have to find and update all the conditionals. But with polymorphism, you just create a new class and provide the appropriate methods. Clients of the class don’t need to know about the polymorphism, which reduces the dependencies in your system and make it easier to update.