Code Refactoring – An Overview
Refactoring is the process of improving the performance of the code after it has been developed by changing only the internal structure and not changing the external functionality of the code. Refactoring improves the non-functional attributes of the application such as readability, maintainability, and extensibility of the code. It also reduces the complexity and can also help software developers to find and fix any hidden bugs in the application by removing unnecessary complexity and by simplifying the program logic.
On the other hand, if the refactoring is not done well, it can lead to the introduction of new bugs in the system or break the existing functionalities. When we are continuously refactoring the code, it becomes more and more easy to work with. However, the need for urgent maintenance activities, need to avoid downtime and the pressure to deliver features to the customer quickly prioritizes the time-to-market factor over the code quality.
Insights on Code Smell
Agile Programmers use the term “Code Smell” to indicate that characteristic of the source code which indicates a deeper problem. The term was coined by Kent Beck in the late 1990s and refers to certain structures in the code that indicate a violation of fundamental design principles that negatively impact design quality. Code smells are not bugs, and they do not prevent the program from functioning. Instead, they indicate some other weaknesses in design that may slow down the development or increase the risk of bugs or failures in the future. Bad code smells can be an indicator of factors that contribute to "technical debt" in the case of agile sprints.
Some common code smells are listed below.
Examples of Application level smells:
a) Duplicated Code: An identical or similar code which is present in more than one location
b) Contrived Complexity: Usage of highly complicated design patterns where simple design would have been sufficient
c) Shotgun Surgery: A lone change needs to be applied across multiple classes at the same time
Examples of Class level smells:
a) Large Class: A class that has become too large
b) Feature Envy: A class which is using the methods of another class in excess
c) Inappropriate Intimacy: a class which has dependencies on the implementation of another class
d) Refused Bequest: A class that overrides a method of a base class in such a way that the contract of the base class is not honored by the derived class
e) Lazy Class / Freeloader: A class that does too little
Examples of Method level smells:
a) Too many parameters: A very long list of parameters is difficult to read. The method call and testing of the function become complicated. It may indicate that the purpose of the function is not well conceived, and the code should be refactored in a way that responsibility is assigned clearly
b) Long method: A method, function, or procedure that has grown too large
c) Excessively long identifiers: The use of naming conventions to provide disambiguation. This should be implicit in the software architecture
d) Excessively short identifiers: The name of a variable should reflect its actual function unless it is self-explanatory
e) Excessive return of data: a function or method that returns more than what each of its callers needs
f) Extreme long lines of code: A line of code which is very long, difficult to understand, to debug, to refactor or to check for reusability options
Visual Studio Refactoring Menu:
Visual Studio Professional Edition contains the Refactor option under the main Edit menu of the IDE. This menu item will get enabled only when a C# file is kept open in the IDE.
In the Visual Studio 2017 Edition, we have the following options under the Refactor menu for refactoring the C# code:
- Extract Method Refactoring
- Rename Refactoring
- Encapsulate Field Refactoring
- Extract Interface Refactoring
- Remove Parameters Refactoring
- Reorder Parameters Refactoring
1. Extract Method Refactoring:
Extract Method is one of the C# refactoring techniques which provides a way to create a new method from a code fragment in an existing member.
Using the Extract Method, we can create a new method by extracting a selection of code from inside the code block of an existing member. The new, extracted method contains the selected code only and the selected code in the existing member is replaced with a call to the new method. Turning a fragment of code into its own method lets us to quickly and accurately reorganize code for better reuse and readability.
1. Select the code fragment you want to extract.
2. On the Refactor menu, click Extract Method.
3. The Extract Method dialog box appears.
Alternatively, we can also type the keyboard shortcut CTRL+R, M to display the Extract
Method dialog box or we can also right-click the selected code, point to Refactor,
and then click Extract Method to display the Extract Method dialog box.
4. Enter a name for the new method in the New Method Name box.
5. A preview of the new method’s signature is shown under the Preview Method Signature.
6. Click OK.
2. Rename Refactoring:
Rename is another C# refactoring technique that provides a way to rename the code identifiers such as fields, local variables, methods, namespaces, properties, and types. Rename can be used to change the names in the comments and in strings also and also to change the declarations and calls of an identifier.
How to Invoke Rename Refactoring:
a. Code Editor: In the Code Editor, rename refactoring is available when you position the cursor on certain types of code symbols. When the cursor is in this position, we can invoke the Rename command by typing the keyboard shortcut (CTRL + R, CTRL + R), or by selecting the Rename command from the shortcut menu or Refactor menu.
b. Class View: When we select an identifier in the Class View, rename refactoring is enabled in the shortcut menu and Refactor menu.
c. Object Browser: When we select an identifier in the Object Browser, the rename refactoring is available only from the Refactor menu.
d. Property Grid: Changing the name of a control will initiate a renaming operation for that control. The Rename dialog box will not appear.
e. Solution Explorer: Rename command is available on the shortcut menu.
1. Field: Changes the declaration and usages of the field to the new name.
2. Local Variable: Changes the declaration and usages of the variable to the new name.
3. Method: Changes the name of the method and all references to that method to the new name including static and instance methods.
4. Namespace: Changes the name of the namespace to the new name in the declaration, all using statements, and fully qualified names.
5. Property: Changes the declaration and usages of the property to the new name.
6. Type: Changes all declarations and all usages of the type to the new name, including constructors and destructors.
3. Encapsulate Field Refactoring:
The Encapsulate Field is a refactoring operation which enables you to quickly create a property from an existing field, and then seamlessly update your code with references to the new property.When any field is declared as public, other objects have direct access to that field and can modify it, undetected by the object which owns the field. By using properties to encapsulate and protect the field, you can disallow any direct access to the fields.
To create the new property, the Encapsulate Field operation first changes the access modifier for the field that we want to encapsulate to private. Next, it generates the Get and Set accessors for that field. In some cases, only a Get accessor is generated, such as when a field is declared as read -only. The refactoring engine now updates the code with references to the new property in the areas mentioned in the Update References section of the Encapsulate Field dialog box.
How to Use:
1. In the Code Editor, place the cursor in the declaration, on the name of the field that you want to encapsulate.
2. On the Refactor menu, click Encapsulate Field.
3. The Encapsulate Field dialog box appears. We can also type the keyboard shortcut CTRL+R, E to display the Encapsulate Field dialog box. We can also right-click the cursor, point to Refactor, and then click Encapsulate Field to display the Encapsulate Field dialog box.
4. Specify settings and Click the OK button.
5. If you selected the Preview reference changes option, then the Preview Reference Changes window opens. Click the Apply button.
4. Extract Interface Refactoring:
Extract Interface is a refactoring operation that provides an easy way to create a new interface with members that originate from an existing class, struct, or interface. When several clients use the same subset of members from a class, struct, or interface, or when multiple classes, structs, or interfaces have a subset of members in common, it can be useful to place the subset of members in a separate interface. The Extract Interface generates an interface in a new file and places the cursor at the beginning of the new file. We can specify which members to extract into the new interface, the name of the new interface, and the name of the generated file using the Extract Interface dialog.
How to Use:
1. With the cursor positioned on the method, click Extract Interface on the Refactor menu. The Extract Interface dialog box appears.
2. We can also type the keyboard shortcut CTRL+R, I to display the Extract Interface dialog box.
3. Or we can also right-click the mouse, point to Refactor, and then click Extract Interface to display the Extract Interface dialog box.
4. Click Select All.
5. Click OK.
5. Remove Parameters Refactoring:
Remove Parameters is a refactoring technique which provides a way to remove parameters from methods, indexers, or delegates. Remove Parameters changes the declaration of the method and at the locations where the member is called, the parameter is removed to reflect the new declaration.
We perform the Remove Parameters operation by first positioning the cursor on a method, indexer, or delegate. While the cursor is in position, to invoke the Remove Parameters operation, click the Refactor menu, press the keyboard shortcut, or select the command from the shortcut menu.
How to Use:
1. Place the cursor on method A, either in the method declaration or the method call.
2. From the Refactor menu, select Remove Parameters to display the Remove Parameters dialog box. We can also type the keyboard shortcut CTRL+R, V to display the Remove Parameters dialog box. We can also right-click the cursor, point to Refactor, and then click Remove Parameters to display the Remove Parameters dialog box.
3. Using the Parameters field, position the cursor on the parameter and then click Remove.
4. Click OK.
5. In the Preview Changes — Remove Parameters dialog box, click Apply.
6. Reorder Parameters Refactoring:
Reorder Parameters is one of the C# refactoring techniques that provides a way to change the order of the parameters for the methods, indexers, and delegates. Reorder Parameters modifies the declaration first and at any locations where the member is being called, the parameters are rearranged as per the new order.
In order to perform the Reorder Parameters operation, place the cursor next to a method, indexer, or delegate. When the cursor is in position, invoke the Reorder Parameters operation by pressing the keyboard shortcut, or by clicking the command from the shortcut menu.
How to Use:
1. Place the cursor on the method, either in the method declaration or the method call.
2. On the Refactor menu, click Reorder Parameters.
3. The Reorder Parameters dialog box appears.
4. In the Reorder Parameters dialog box, select the parameter in the Parameters list, and then click the down button. Alternatively, you can drag the parameter after the destination parameter in the Parameters list.
5. In the Reorder Parameters dialog box, click OK.
6. If the Preview reference changes option is selected in the Reorder Parameters dialog box, the Preview Changes - Reorder Parameters dialog box will be displayed. We can see the preview of the changes in the parameter list for the Method in both the signature as well as the method call.
7. If the Preview Changes - Reorder Parameters dialog box appears, click Apply.
Thus, code refactoring continues to be an important practice that must be done frequently and concurrently in order to reduce the complexity of the code. The benefits of refactoring are multi-dimensional, therefore the developers and managers would be benefitted from the automated tool support for monitoring the impacts of refactoring.