Main points of this paper:

  1. What project, and why is it refactoring?
  2. How did you reconstruct it?
  3. Before and after reconstruction

What project, and why is it refactoring?

The project is the visualization sub-project of one of the company’s main business products. There is almost no coupling with other sub-projects, so it can be carried out separately for reconstruction. The specific business is not described too much, and the main reconstruction content is system components and a self-developed visual graphics library. The refactoring took a total of 30 working days.

The main technology is Vue2 series and JavaScript. The first reason for refactoring is the absence of static typing, which means that viewing an object structure requires searching through multiple files. Second, the pattern of newly added codes before is generally “one requirement plus one code”. Long-term accumulation leads to confusion in code structure and poor readability. Thirdly, the coupling degree of each state module is high, which increases the difficulty of code maintenance.

How did you reconstruct it?

Use TypeScript in JavaScript. “What? Using TS in JS? Never heard of it.” I was thinking the same thing until I read the last item in the TS official website manual: “Type Checking JavaScript File”. In fact, TS and VSCode (an IDE) can also implement static type detection, but in the form of comments, tsconfig.json and custom Typing are also supported.

type TypeApple = { name: string, count: number }
Copy the code
/** @type {TypeApple} */
const apple = { name: 'foo'.count: 100 }
Copy the code

Second, refine module classification. In general, modules are coupled. But if the coupling degree is too high, it is often because the module is not subdivided in place. How to refine the module? For example, suppose you have a module called Operation that contains both operation-related logic and operation-panel logic. As the business grows, the operation panel logic becomes more and more. It is entirely possible to separate the action panel logic into a module, OperationPanel.

Decoupling visual library and Vue/Vuex. When writing business, it is easy to write longer and harder to maintain code in Vue components or Vuex modules because of convenience. This project is no exception. Therefore, in the process of reconstruction, the visuality-library related series are separately divided into modules and managed by Vuex notation (state, getters, Mutations, Actions).

class Counter {
  // # state  
  /** @type {number} */
  count = 0

  // # getters
  get countText() { return `Count is: The ${this.count }` }

  // # mutations
  /** @param {number} count*/
  SET_COUNT = count= > { this.count = count }
  
  // # actions
  /** @param {number} count*/
  logCount = ( count ) = > {
    this.SET_COUNT( count )
    console.log( this.countText )
  }
}
Copy the code

Finally, write maintainable code. There are two methods.

The first one is “Use Map”. There are three common methods to deal with “one multi-type data” : If, Switch and Map. The use of “If” is simple and easy to understand.

if ( animalType === 'dog' ) {
    console.log( 'Wang! ')}else if ( animalType === 'cat' ) {
    console.log( 'Miao! ')}else if ( animalType === 'bird' ) {
    console.log( 'Jiu! ')}Copy the code

Switch can be seen as a simplification of If.

switch ( animalType ) {
    case 'dog':
      console.log( 'Wang! ' )
      break
    case 'cat':
      console.log( 'Miao! ' )
      break
    case 'bird':
      console.log( 'Jiu! ' )
      break
}
Copy the code

Map is the most targeted, concise, and easy to maintain.

const logMap = {
    dog: (a)= > console.log( 'Wang! ' ),
    cat: (a)= > console.log( 'Miao! ' ),
    bird: (a)= > console.log( 'Jiu! ' ),
}
logMap[ animalType ]()
Copy the code

The exact usage varies from scenario to scenario, but in most scenarios, using a Map is more readable.

The second is “Use getters and Mutations.” For example, define a module called operationGetters.js that provides various constants and methods for retrieving operations.

export const OPERATION_TYPE_A = 0
export const OPERATION_TYPE_B = 1

export const OPERATION_TITLE_MAP = {
  [ OPERATION_TYPE_A ]: 'Title A',
  [ OPERATION_TYPE_B ]: 'Title B',}export const getOperationTitleByType = type= > OPERATION_TITLE_MAP[ type ]
Copy the code

Defining mutations defines a file that provides methods for changing data. When maintaining code, looking for the change method name leads directly to the source of the change data.

export const SET_OPERATION_TITLE = ( operation, title ) = > { operation.title = title }
Copy the code

Before and after reconstruction

Code type Before the refactoring After the reconstruction
Visual tool library 245kb 214kb
component 171kb 157kb
State management 62kb 60kb
Module model 15kb 19kb
The service request 12kb 4kb
constant 18kb 22kb
Tools (Utils) 15kb 19kb
Static typing (TypeScript) 0kb 9kb
A combined 521kb 509 kb

Because new functionality is being added as you refactor, and code defining TypeScript static types is being added, the total amount of code is not significantly reduced.

However, performance has improved significantly and, most importantly, code has become much more readable and maintainable, making it easier to cope with new requirements.

Thank you for taking the time to read this article. If you like this article, please like, bookmark and share, so that more people can see this article, which is also the biggest encouragement and support for me! Welcome to Star and subscribe to my original front-end technology blog.