Most of the time, we see some not very elegant code, not very clean code, it is easy to infer how the code came from, or even can infer the psychological state of the person who wrote the code and the background at that time. In the era of rapid development of the front-end, a code of more than one year or two years is likely to become a historical burden with the color of history
Archaeological 🔍
If, one day, you suddenly see code like the following:
Multiple if – return
function f() {
if (a) {
return
}
if (b) {
return
}
if (c) {
return
}
/ /... many codes
}
Copy the code
Conjecture the psychology of the party: need to do this function, need to add a condition. All right, just add it up front
The function takes many arguments
function f(a, b, c, d, config, isAdmin, isEdit, isAdd) {
/ /... many codes
}
Copy the code
Infer the psychology of the parties: the function is more complex, and it needs to add one more parameter to configure. Ah, a few more functions, one more parameter
A long similar judgment
if (a === 1 || a === 2 || a === 3 || a === 4) {}Copy the code
Conjecture party psychology: state 4 also want to walk this logic, that I add more && can
Component return value has redundant short-circuit expression
return (
<>
{
isXXX && <div>abc</div>} {/* There may be a lot of other code in the middle */} {! isXXX &&<div>123</div>
}
</>
)
Copy the code
Conjecture party psychology: dou bottom circumstance shows 123, add directly, ok
Apparently impossible logic
const data = res[0].some_data || {}
if(! data) {return
}
// other code
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
const SOME_FLAG1 = 'xxxx1'
const SOME_FLAG2 = 'xxxx2'
const SOME_FLAG3 = 'xxxx3'
const arr = [SOME_FLAG1]
if (xxx) {
// arr
}
// Perform an operation on arR
if(! arr) {// Afraid of making mistakes? Add the
}
Copy the code
Infer the psychology of the parties 1: arR may be false to prevent error reporting
Conjecture party psychology 2: just changed front, back! Arr didn’t see it
Common snippets of code appear out of nowhere
import { func } from 'prop-types';
function a(){
return 1
}
Copy the code
I just typed func and pressed enter, thinking it was function completion
Want some common utility functions but have more than one code prompt
Another example is to want a request and find more than three prompts. Then look, the team unified request one, someone wrote a cached version another, another person wrote their own pocket version, and finally another person wrote a preprocessor parameter…
1. I didn’t know there was a unified request of the team. I wrote it myself and it was very bad
2: I knew there was a request, but I was afraid to change it, so I packaged an extra layer, but the name was still the same
A refurbished 🔧
Open eslint/tslint
In my experience with code optimization and refactoring, a project without Lint can use Autofix tofix 90% of its errors. For example, 9000 errors can become more than 800 in a run, which fixes the problem of line breaks, indentation, and functions with single arguments without parentheses. These fixes do not require test intervention. The rest of the errors need to be fixed manually
The most common set of Lint errors that require manual resolution:
error | The solution | The degree of emergency | risk |
---|---|---|---|
Underline naming | Global search, one manual repair | In the | low |
Deconstruction assignment | The value is usually a warning | low | low |
Stateless class components | Change to PureComponent or function component | high | In the |
willreciveprops | To getderivedstatefromprops | high | high |
componentwillmount/update | Initial state & didmount | high | low |
= = | Determine the type and then convert, and finally === = | high | high |
Duplicate names under scope | Fix it when you see it, but it’s still necessary | In the | low |
The TS type is incorrect | It does not affect the execution of the code, but it cannot be neglected for a long time | low | low |
HTML tags lack attributes | Such as IMG Alt, button type, see the repair | low | low |
Rejcet of promise is not an error | reject(Error(xxx)) | high | low |
Repair of medium risk above, need self-test or test, go through the main process. Any artificial repair, numbering in the hundreds, requires testing intervention
To streamline the if
Such as the multiple if above – return, long similar judgment, can reduce to | |, &&, further streamline is an array of operations: [1, 2, 3, 4]. Includes (a), there is a talk about more in another article if simplified
Take a look at the entire file context
In some of the cases mentioned above, the design may start out fine, but as requirements iterate, it changes. For example, multiple if-returns, obvious logic failure, and repeated writing of common utility functions are all caused by incomplete reading of the context
React upgrade migration
- When the old version is upgraded to a new one, three Danger life cycles must be dealt with, among which GetderivedStateFromprops has the greatest risk and needs to make various judgments
- Try hook rewriting simple components (no need to go out of your way, just change where the requirements are covered)
- When refactoring a class component that uses a ref or context into a function component, take sufficient precautions such as forwardRef or useContext
- Components must have names, no
export default class extend
,export default function() {}
Otherwise, the debugger does not display the name - If it’s not a TS project, use props-types (or write a d.ts file next to it)
- Render function returns content, function components return content should not be too long, must do a good component separation. For complex JS operations, it is recommended to extract components or renderxxx functions
Refactoring steps
I have many historical reconstruction experiences of large projects. Common cases and routines have been mentioned above. The following is a summary of the operation steps
No matter what happens, lint
Traditional older projects, which usually don’t have Lint, need to install their own. Then look for your team’s current Lint specification (if not, use an industry name like Airbnb) and run a wave of Lint fixes that will fix all the indentation and line feeds, leaving you to manually fix the rest. How to repair manually, as mentioned above
Edit the file by the way.
Why refactor? There must have been a trigger, or a requirement, or a lot of bugs found that didn’t work. Or start a vigorous maintenance program. So start from the trigger point, in the case of ensuring normal function, incidentally, the module is reconstructed together, there are also a few key points:
- The new logic must have annotations. If the old logic does not have annotations, but is associated with this modification, comb it or ask colleagues to understand the background and complete the annotations and documents
- Stateless class component, which can be changed to pureComponent. If you want to embrace hooks, you have to change the function component. But there is one cavtake: do a global search to make sure that no other place extends the current class component
- Process all magic numbers. When you see
if status === 1
,type === 0
This code, this confusing number, is the Magic number. Now look at the following to see what this number means, andUse uppercase constantsTo maintain (e.gconst NORMAL = 1;
And add a note:// [xx module] Normal: 1
). If more than one file is used, it needs to be extracted to a higher level - Weird naming can also be fixed in this section. In-file search, non-object key, non-deconstruction, can be replaced directly
- If you are not sure, dare not change, or have questions, use TODO comments to mark them for easy follow-up. Such as
if a == b
Can’t know what type a and B are from the code, and the service path is too long to reproduce, first compromise, wait for time to change - For functions that are “unreadable” or “dare not change,” treat them like a sandbox. Keep in mind that the upstream input of this code is unchanged
- For repetitive code, a function needs to be extracted and then imported to be called. There is no need for excessive encapsulation, perhaps a thin layer of encapsulation, to eliminate the obvious excess of duplicate code
- If lint finds an error for not defined but the page is fine, there are only two cases: the file is useless or the file hasn’t been executed yet. If it doesn’t work, delete it immediately. If not, you can either disable the esLint error and add TODO to it, or define it so that it can be executed normally with no side effects (it’s best to ask a colleague about this).
How to determine the scope of modification?
There is a file directory like this:
- components
utils.ts
constant.ts
-- Home
index.tsx
Header.tsx
Footer.tsx
.
-- Input
index.tsx
index.scss
.
Copy the code
- If I change it to be
Header.tsx
The Home directory is not large and needs to be reconstructed together. If the Home directory is large, just change itHeader.tsx
And its parent componentindex.tsx
- If there are any constants in the Home and Input that cause a magic number, you must add a new definition in the constant and comment it out before importing it into the component
- If Home is large and multiple files import a function that has been determined to be useless or needs to be removed, then you need to search globally for the statement under Home and delete it or remove it. Okay
Repair infrastructure
The functionality is done, and there’s been a wave of refactoring, but that’s not the end of it. With future maintenance and refactoring in mind, start paving the way now for the next time and make yourself and your colleagues more comfortable
- For new and key functions, you need to write your own name, date, comment, and even post links to references on the web
- Check your TODO periodically. Don’t mark TODO and leave it at that, check it regularly and follow up when you have time
- Lint-staged hooks will not be submitted if they fail
- The public utils, Common, and Assets folders are all common resources. These folders need to be extracted based on common business elements, including utility functions, common components, global configuration, and definition files
- Readme complete documentation, including page logic, file directory organization, and development specifications, is up to you at this point
- Js to TS project, part of the migration, is also changed to where, where ts. For the time being, it is not possible to access the large component of TS. It is also possible to make a type declaration for a D.ts file
- You can only use the following command to curl a parameter: In the middle layer of node, params passes directly from the front end to another service, and Response passes directly from the other service back to the front end, or
{ ...data }
Experienced people naturally understand the pain
conclusion
Although usually we always black, tell jokes, from black, ridicule emoticons, ridicule garbage code, historical code, know it is useless but dare not move. But I believe that if it is really put on the head, people will not be afraid, will not easily compromise, will seriously fix, perfect refactoring
Pay attention to the public account “Different front-end”, learn front-end from a different perspective, grow fast, play with the latest technology, explore all kinds of black technology