TOP
What is refactoring?
Description
Refactoring (Refactoring) – changes made to the internal structure of software (software) to make it easier to understand and faster to modify without changing external behavior. Also, it is a restructuring of the software through the application of a sequence of refactorings without changing the external behavior of the software.
Advantages of refactoring:
- Refactoring improves software design. Over time, many additional changes are made to the code and the software loses its structure over time. The loss of structure has a cumulative effect. The harder it is to see the design in the code, the harder it is to keep it and the faster it falls apart. Also, such changes cause redundancy and duplication of code, making the system more difficult to understand and modify.
- Refactoring makes software code more understandable.
When you need to do refactoring:
- When a new feature is added;
- When an error is corrected (fixed);
- During code review.
Bad smells in the code (Smells Catalog) :
- Code duplication
- Long method
- Big class
- A long list of parameters
- Divergent modifications
- Shot shooting
- Envious features
- Blocks of data
- Obsession with elemental types
- Switch operators
- Parallel hierarchies of imitation
- Lazy class
- Speculative (theoretical) community
- Temporary field
- Message threads
- Agent
- Inappropriate proximity
- Alternative classes with different interfaces
- Incomplete library class
- Data classes
- Comments
Possible refactoring options
-
Moving Features Between Objects (Transfer of complete code between objects):
- Move Method (Method highlighting) – isolate a separate method if the method is too long or contains code that requires comments.
- Move Field (Moving field) – performed when the field is used by another class more often than where it is defined.
-
Organizing Data (Data arrangement):
- Encapsulate Field (Field Encapsulation) - one of the main principles of OOP is encapsulation, or data hiding. By making data public, objects can read and change its values without the knowledge of the data owner. Therefore, we make such a field closed and provide access methods.
- Encapsulate Collection (Collection encapsulation) - often the classroom contains a collection of specimens. This collection can be an array, list, set, or vector. The getter method should not return the collection object itself, because that would allow clients to modify the contents of the collection without the knowledge of the class that owns it. Therefore, you need to make the value returned by the read-only method and create methods to add/remove elements.
-
Composing Methods (Extracting and combining code):
- Extract Method (Method highlighting) – if there is a piece of code that can be grouped, put that piece in a separate method with a name that explains its purpose. Thus, the method name will replace the comments.
- Inline Method (Method embedding) – sometimes it is useful to move the body of a method into the code that calls it. Sometimes method bodies are as self-explanatory as the method name itself. There may also be a situation when there are many different methods, the structure of which is unsuccessful, and therefore it is better to drop them all into one general method, and then separate the methods in another way.
- Inline Temp (Insertion of a temporary variable) – replacement of a temporary variable to which a simple expression is assigned only once. Sometimes such a variable interferes with other refactorings.
- Replace Temp with Query (Replacing a temporary variable with a method call) – is used when a temporary variable is used to store the value of an expression. In this case, we replace the expression with a method and replace all references in the code to this variable with the new method.
- Split Temporary Variable (Split a temporary variable) – applies if a single temporary variable is used to assign multiple results to different results (unless it is a variable used in a loop within a loop and is not a variable to accumulate the result). In this case, we create a separate variable for each assignment.
-
Simplifying Conditional Expressions (Simplifying expressions with conditions):
- Decompose Conditional (Decomposition of the conditional operator) – executed when we have a conditional chain of checks (if-then-else). We replace the condition (if), parts of then and else with separate methods. Contributes to a better understanding of the reason for branching, and method names clarify the purpose of the corresponding piece of code.
- Consolidate Conditional Expression (Consolidation of conditional expression) - is carried out if there are a number of condition checks that give the same result. You need to combine all checks into a single conditional expression or method.
- Consolidate Duplicate Conditional Fragments (Consolidation of duplicated conditional fragments) – the same fragment is present in all branches of the conditional expression. You need to move this piece of code outside of this expression.
- Remove Control Flag (Removing control flag) – there is a variable that acts as a control flag for a series of logical expressions. We use BREAK or RETURN instead.
- Replace Conditional with Polymorphism (Replacing the conditional operator with polymorphism) – is performed when there is a conditional operator whose behavior depends on the object type. It is necessary to move each branch of the conditional operator into an overloaded method of the subclass. Make the source code abstract.