It is quite common to see bad and smelly code. Refactoring is all about clean code: identifying the bad smells in code and transforming the code to make it better.
In this article, we discuss how to automate most of the refactoring tasks. For illustration we are using Rider (Rich IDE from JetBrains). Identifying smells and refactoring is made incredibly easy because most of it is automatic with Rider! Just point and click/select options to see the magic unfold!
Rider often identifies / indicates bad smells in code.
To refactor, you need to select appropriate refactoring action from one of:
- “Refactor” menu option
- “Refactor This” option with Shift + Cmd + R
- Clicking the Yellow bulb
- Invoke "Context action" with Alt + Enter
Let's jump in with smells examples and how to refactor them.
Large methods are one of the biggest enemies of readability. It is easy to end-up with excessively long methods with 100s of lines of code.
A rule of thumb is that the entire method code should be visible within your screen (and reducing the font size of zooming out is not the right fix :-p)
Methods should read like steps. So, extract code segments into separate private helper methods. Tip: Look out for new lines - they indicate logical breaks in the method and they blocks separated by newlines belong in separate methods!
Applications can easily break with missing validation checks. Examples: null checks and check if collection is empty.
Code defensively and add these validation code automatically. Just point on the parameter and click the hammer icon and add the checks! Or on the parameter press Alt + Enter to add these checks - just like magic!
You can refactor ‘Magic Strings’ with named variables or constants.
"Magic strings" are hardcoded strings in the programs. Though its extremely convenient to just embed the required strings in the program, it is a bad practice & a smell. Refactor them to named constants or variables. If needed extract them into resource files for internationalization. It’s easy to extract variable or inline variable with just context actions
When you have large static methods in a class, it is often an indication that the method belongs to a class on its own. For example, consider a large method in a class named AirQualityReporter named ReadXLS - that reads pollution readings from an Excel file.
Reading a XLS file should be handled by a separate abstraction. So the smell is "missing abstraction" and the refactoring is "extract class".
This short video shows how. Note that the extracted class XLSReport need further refactoring since its a large method with more than one responsibilities. Of course, that's the topic of another video :-)
To control object creation, we need to use factory methods.
In many contexts, we want to control object creation. For example, reuse objects instead of creating them again and again (as in Flyweight pattern) or restrict the number of objects created (as in Singleton). With a publicly available constructor, that becomes not possible. Invoke refactor this by adding a factory method and make the constructor protected in a click or two!
Large parameters and data clumps are common smells in large codebases. Rule of thumb - if >4 parameters, consider refactoring.
'Data clumps' refer to related parameters that are always passed and used together - that indicates they belong in a separate data class.
With “Transform Parameters” refactoring, extracting data clumps to data classes is as easy as blinking the eye!
Think about UI widets. The base type Widet doesn't exist in the real-world and it abstracts various concrete widgets such as TextWidget, ScrollBar, Grid etc. So the base type Widget is best expressed as an abstract class.
Consider 'Scrollable' - not all UI Widgets are scrollable. And Scrollable doesn't have concrete behavior - it just provides methods such as ScrollUp and ScrollDown. So its best expressed as an interface.
If you have created an abstract class instead of an interface (and vice versa), you can do it automatically in Rider (Rich IDE for .NET). Just point at the abstract class or interface and press Shift + Cmd + R and you can change its form from one to another.
This is a small article and we have just scratching the surface! Just as a quick summary, here is the list of smells and refactorings we have covered so far:
- “Large Methods” => Extract “Helper Methods”
- “Unchecked Methods” => Add Parameter Validation to Methods
- “Magic Strings” => Extract constants / variables
- “Large static methods” => Extract class
- Unconstrained constructors => Factory Method
- “Data Clumps” & “Long Parameter Lists” => Extract data classes
- Inappropriate abstract class => Transform to interface
Refactoring is all about repeatedly improving the existing code. When we get some code working and leave it there, it will be certainly be smelly. However, if we revisit the code and improve it, the code quality improves dramatically.
Fortunately, such improvement can be done sort of "auto-magically" with the powerful IDEs like Rider. For example, consider renaming a variable/method/class/etc. Renaming manually is prone to errors and time consuming. And its so easy to rename with Rider - just point on the name and press Alt + Enter => "Refactor This" => "Rename" and boom, the refactoring is done!
Also, there is no need to remember “too many” shortcuts!
- Select “Refactor” menu option
- Invoke “Refactor This” with Shift + Cmd + R
- Get “Context Actions” with Alt + Enter
Hope you explore powerful refactoring features of Rider & ReSharper and make your code clean and higher quality.