Code Refactoring
To summarize knowledge learned from https://refactoring.guru/refactoring.
Why code refactoring is needed?
Everyone does their best to write excellent code from scratch. There probably isn’t a programmer out there who intentionally writes unclean code to the detriment of the project.
Question: At what point does clean code become unclean?
Answer: When we keep increasing Technical Debt to the project.
What is technical debt?
If you get a loan from a bank, this allows you to make purchases faster. You pay extra for expediting the process — you don’t just pay off the principal, but also the additional interest on the loan.
The same thing can happen with code. You can temporarily speed up without applying sufficient best practices, but this will gradually slow your progress every day until you eventually have to pay the debt off, for instance rewriting the whole project from scratch.
Causes of technical debt
1. Business pressure: Sometimes business circumstances might force you to roll out features before they’re completely finished.
2. Lack of understanding of the consequences of technical debt: This can make it too difficult to dedicate the team’s time to refactoring because management doesn’t see the value of it.
3. Failing to combat the strict coherence of components: Any changes to one part of the project will affect others. This can happen because of the tight coupling of code structure.
4. Lack of tests: Even a tiny change can produce the worst bugs on production if we don’t run any tests.
5. Lack of documentation: This slows down the introduction of new people to the project and can grind development to a halt if key people leave the project.
6. Lack of interaction between team members: If the knowledge base isn’t distributed throughout the company, people will end up working with an outdated understanding of processes and information about the project.
7. Long-term simultaneous development in several branches: This can lead to the accumulation of technical debt, which is then increased when changes are merged.
8. Delayed refactoring: At some point, some code may become obsolete, cumbersome, or must be redesigned, if we keep postponing refactor them, more dependent code will have to rework.
9. Incompetence: This is when the developer just doesn’t know how to write decent code.
How to do code refactoring?
Refactoring should be done as a series of small changes, each of which makes the existing code slightly better while still leaving the program in working order.
1. Detect code smells
1.1 Bloaters
Bloaters are code, methods, and classes that have increased to such gargantuan proportions that they are hard to work with. Usually, these smells do not crop up right away, rather they accumulate over time as the program evolves (and especially when nobody makes an effort to eradicate them).
- Long Method: A method contains too many lines of code. Generally, any method longer than ten lines should make you start asking questions.
- Large Class: A class contains many fields/methods/lines of code.
- Primitive Obsession: Creating some primitive fields is so much easier than making a whole new class, right? Later others do the same then code get dirty.
- Long Parameter List: More than three or four parameters for a method.
- Data Clumps: Sometimes different parts of the code contain identical groups of variables (such as parameters for connecting to a database). These clumps should be turned into their own classes.
1.2 Object-Orientation Abusers
- Alternative Classes with Different Interfaces: Two classes perform identical functions but have different method names.
- Refused Bequest: If a subclass uses only some of the methods and properties inherited from its parents, the hierarchy is off-kilter.
- Switch Statements: You have a complex switch operator or sequence of if statements.
- Temporary Field: Temporary fields get their values only under certain circumstances. Outside of these circumstances, they’re empty and redundant.
1.3 Change Preventers
These smells mean that if you need to change something in one place in your code, you have to make many changes in other places too. Program development becomes much more complicated and expensive as a result.
- Divergent Change: You find yourself having to change many unrelated methods when you make changes to a class.
- Shotgun Surgery: Making any modifications requires that you make many small changes to many different classes.
- Parallel Inheritance Hierarchies: Whenever you create a subclass for a class, you find yourself needing to create a subclass for another class.
1.4 Dispensable
A dispensable is something pointless and unneeded whose absence would make the code cleaner, more efficient, and easier to understand.
- Comments: A method is filled with explanatory comments.
- Duplicate Code: Two code fragments look almost identical.
- Lazy Class: Components that are near-useless or a super small class.
- Data Class: A data class refers to a class that contains only fields and crude methods for accessing them (getters and setters).
- Dead Code: A variable, parameter, field, method, or class is no longer used (usually because it’s obsolete).
- Speculative Generality: There’s an unused class, method, field, or parameter.
1.5 Couplers
All the smells in this group contribute to the excessive coupling between classes or show what happens if the coupling is replaced by excessive delegation.
- Feature Envy: A method accesses the data of another object more than its own data.
- Inappropriate Intimacy: One class uses the internal fields and methods of another class.
- Message Chains : In code you see a series of calls resembling $a->b()->c()->d().
- Middle Man: If a class performs only one action, delegating work to another class, why does it exist at all?
1.6 Other Smells
- Incomplete Library Class: Sooner or later, libraries stop meeting user needs. The only solution to the problem — changing the library — is often impossible since the library is read-only.
2. Apply code refactoring techniques
There are 6 categories of refactoring techniques i.e. composting methods, moving features between objects, organizing data, simplifying conditional expressions, simplifying method calls, and dealing with generalization. There are 66 techniques in total. View more about each technique in the below document.