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, noexport 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 seeif status === 1,type === 0This 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 asif a == bCan’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 beHeader.tsxThe Home directory is not large and needs to be reconstructed together. If the Home directory is large, just change itHeader.tsxAnd 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