×
Community Blog The Refactoring Principle and Why It Matters to Anyone Coding

The Refactoring Principle and Why It Matters to Anyone Coding

Chanyi shares his thoughts about methods that you can use to code and the current situation of coding, considering the problem of the refactoring principle.

By Chen Changyi, nicknamed Chang Yi, is a technical expert in the AutoNavi team at Alibaba.

Don Roberts proposed a refactoring principle, which is as follows:

When you do a task for the first time, you only need to do it. When you do a similar task for the second time, you may feel a bit reluctant, but still manage to do it. When you do the task for the third time, you should think about refactoring.

The same is true for coding. When writing similar code multiple times, we need to think whether there is a way to increase the coding speed. As someone who has been engaged in agile development for several years, in this article I would like to summarize some coding methods here to help programmers write code in a faster and more efficient way.

Method 1: Manually Write Code

Most novice JAVA programmers may type out the following code on the development tool simply by muscle memory:

public class Test {
    public static void main(String[] args) {
        System.out.println("Hello world!");
    }
}

Yes, this is the classic "Hello world" statement, the one everyone learns when they first code.

Naturally manually entering code is an option. And in actuality, manually entering code is a good test of someone's competence as a programmer. In fact, many companies use manual coding as part of a computer programming examination during the interview process. During such exams, the interviewee needs to select a programming tool (such as Eclipse) based on the examination requirements, and then manually write, debug, and run some specific code. During the entire coding process, the interviewee cannot search for answers on the Internet or view any online help documentation. Generally the requirements are that the interviewee must be able to write the code completely by him or herself. Such examination tests the interviewee's coding abilities, including the syntax, function, logic, thinking, algorithm, and hands-on abilities.

Manual coding is a basic skill that any good programmer should and really must have. Manual coding is like the basic writing skills needed to write an article. Syntax is the method for making sentences in code. Functions are the words and sentences in the article. The class libraries are anecdotes for quoting. The architecture is the genre for expressions. The functionality is the main purpose of writing the article. The algorithms are the logic for organizing the language. Therefore, you need to master the syntax of a programming language, learn a bunch of functions of basic class libraries, quote some required third-party class libraries, select a mature and stable architecture, clarify the functions of product requirements, and select an algorithm to realize the logic. Then, manual coding is as easy as writing an article.

Method 2: Copy and Paste Code

As the saying goes in China: "If you study 300 Tang poems well, and you can recite those poems even if you can't write them." The same is true for coding. The first step of coding is imitation. That is, copy and paste code. Copying and pasting code is an art. When properly used, this method allows you to complete coding with half the effort. However, code that is not tested is incredible. When you see the code that you need, carefully check the code before copying and pasting it. Code suitable for one scenario may not be necessarily suitable for another scenario. A qualified programmer cannot simply take and use the code without checking it.

1. Why Copy and Paste Code

  1. Copying and pasting the existing code can save development time.
  2. Copying and pasting the stable code can reduce the risk of system failure.
  3. Copying and pasting the network code can convert others' achievements into your own.

2. Problems Caused by Copying and Pasting of Code

  1. How much do you understand the copied code? Is the implementation logic reasonable? Can the code run stably? How many potential bugs exist?
  2. How many times has the code been copied and pasted in the project? Based on the principle of "refactoring upon the third time you do the same thing", do you need to refactor the same code?
  3. The more times the code is copied and pasted, the more code maintenance problems will arise. To keep the code synchronized after the code is updated in multiple versions, you must make the same changes at each place. This increases the maintenance costs and risks.

In short, copying and pasting code is like other coding methods, and no one method is superior to any of the others. It is just a method that you can use either properly or improperly. If you copy and paste code, you must be responsible for the results.

Method 3: Generate Code by Means of Text Replacement

1. Example of Generated Code

The following is a piece of code that has been written to implement user query:

/** Query user service function */
public PageData<UserVO> queryUser(QueryUserParameterVO parameter) {
    Long totalCount = userDAO.countByParameter(parameter);
    List<UserVO> userList = null;
    if (Objects.nonNull(totalCount) && totalCount.compareTo(0L) > 0) {
        userList = userDAO.queryByParameter(parameter);
    }
    return new PageData<>(totalCount, userList);
}

/** Query user controller function */
@RequestMapping(path = "/queryUser", method = RequestMethod.POST)
public Result<PageData<UserVO>> queryUser(@Valid @RequestBody QueryUserParameterVO parameter) {
    PageData<UserVO> pageData = userService.queryUser(parameter);
    return Result.success(pageData);
}

If you want to write code to implement company query, the code format is similar to the user query code. The replacement relationship can be sorted out as follows:

  1. "User" should be replaced by "Company".
  2. "user" should be replaced by "company".

You can use a text editor, such as Notepad or EditPlus, to replace the common text in case-sensitive mode. The final result is as follows:

/** Query company service function */
public PageData<CompanyVO> queryCompany(QueryCompanyParameterVO parameter) {
    Long totalCount = companyDAO.countByParameter(parameter);
    List<CompanyVO> companyList = null;
    if (Objects.nonNull(totalCount) && totalCount.compareTo(0L) > 0) {
        companyList = companyDAO.queryByParameter(parameter);
    }
    return new PageData<>(totalCount, companyList);
}

/** Query company controller function */
@RequestMapping(path = "/queryCompany", method = RequestMethod.POST)
public Result<PageData<CompanyVO>> queryCompany(@Valid @RequestBody QueryCompanyParameterVO parameter) {
    PageData<CompanyVO> pageData = companyService.queryCompany(parameter);
    return Result.success(pageData);
}

If you generate code by means of text replacement, the code generation time does not exceed one minute.

2. Advantages and Disadvantages

Advantages:

  1. The code generation speed is fast.

Disadvantages:

  1. The sample code must be compiled.
  2. This method is only applicable to the text replacement scenarios.

Method 4: Use an Excel Formula to Generate Code

Excel formulas are very powerful and can be used to compile some formulated code.

1. Use an Excel Formula to Generate a Model Class

Copy the interface model definition from Wiki to Excel. The sample data is as follows:

1

Write an Excel formula as follows:

= "/** "&D6&IF(ISBLANK(F6), "", "("&F6&")")&" */ "&IF(E6 = "否", IF(C6 = "String", "@NotBlank", "@NotNull"), "")&" private "&C6&" "&B6&";"

Use the formula to generate the code as follows:

/** User ID */ @NotNull private Long id;
/** Username */ @NotBlank private String name;
/** User gender (0:unknown;1:male;2:female) */ @NotNull private Integer sex;
/** User description */  private String description;

Create a model class and organize the code as follows:

/** User DO Class */
public class UserDO {
    /** User ID */
    @NotNull
    private Long id;
    /** User Name */
    @NotBlank
    private String name;
    /** User gender (0:unknown;1:male;2:female) */
    @NotNull
    private Integer sex;
    /** User description */
    private String description;
    ......
}

2. Use an Excel Formula to Generate an Enumeration Class

Copy the enumeration definition from Wiki to Excel. The sample data is as follows:

2

Write an Excel formula as follows:

="/** "&D2&"("&B2&") */"&C2&"("&B2&", """&D2&"""),"

Use the formula to generate the code as follows:

/** empty(0) */NONE(0, "Unknown"),
/** male(1) */MAN(1, "Male"),
/** female(2) */WOMAN(2, "Female"),

Create an enumeration class and organize the code as follows:

/** User gender enumeration class */
public enum UserSex {
    /** enumeration definition */
    /** empty(0) */
    NONE(0, "unknown"),
    /** male(1) */
    MAN(1, "male"),
    /** female(2) */
    WOMAN(2, "female");
    ......
}

3. Use an Excel Formula to Generate Database Statements

The company list is sorted as follows in Excel. Based on this list, you need to write SQL statements to insert the records directly into the database.

3

Write an Excel formula as follows:

= "('"&B2&"', '"&C2&"', '"&D2&"', '"&E2&"'),"

Use the formula to generate SQL statements as follows:

('AutoNavi', 'First Tower', '(010)11111111', 'gaode@xxx.com'),
('Alibaba Cloud', 'Green village', '(010)22222222', 'aliyun@xxx.com'),
('Cainiao', 'Alibaba offices', '(010)33333333', 'cainiao@xxx.com'),

Add the into statement header and sort the SQL statements as follows:

insert into t_company(name, address, phone, email) values
('AutoNavi', 'First Tower', '(010)11111111', 'gaode@xxx.com'),
('Alibaba Cloud', 'Green village', '(010)22222222', 'aliyun@xxx.com'),
('Cainiao', 'Alibaba offices', '(010)33333333', 'cainiao@xxx.com');

4. Advantages and Disadvantages

Advantages:

  1. This method is applicable to generation of code for table-based data.
  2. After writing the formula, you can drag and drop the formula to generate code. Therefore, the code generation speed is fast.

Disadvantages:

  1. This method is not applicable to generation of code with complex functions.

Method 5: Generate Code by Using Tools

That is, use an existing tool to generate code. Many development tools provide tools to generate code, for example, to generate constructors, reload base classes or interface functions, generate Getter/Setter functions, and generate toString functions. These tools save the trouble of manual coding. You can also use some code generation plug-ins to generate code that meets certain application scenarios.

The following takes the MyBatis-Generator plug-in as an example to explain how to use a tool to generate code.

1. Installation and Running of the Plug-in

For more information, search for related documents on the Internet.

2. Examples of Generated Code

2.1. Generate the Model Class Code

The content of the User.java file is as follows:

......
public class User {
    private Long id;
    private String user;
    private String password;
    private Integer age;
    ......
}

2.2 Generate the Mapper Interface Code

The content of the UserMapper.java file is as follows:

......
public interface UserMapper {
    User selectByPrimaryKey(Long id);
    ......
}

2.3. Generate the Mapper XML Code

The content of the UserMapper.xml file is as follows:

......
<mapper namespace="com.test.dao.UserMapper" >
  <resultMap id="BaseResultMap" type="com.test.pojo.User" >
    <id column="id" property="id" jdbcType="BIGINT" />
    <result column="user" property="user" jdbcType="VARCHAR" />
    <result column="password" property="password" jdbcType="VARCHAR" />
    <result column="age" property="age" jdbcType="INTEGER" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, user, password, age
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
    select 
    <include refid="Base_Column_List" />
    from test_user
    where id = #{id,jdbcType=BIGINT}
  </select>
  ......
</mapper>

3. Advantages and Disadvantages

Advantages:

  1. The code generation plug-in is used to generate code. Therefore, the code generation speed is fast.
  2. The plug-in configuration file is used to control generation of desired functional code.

Disadvantages:

  1. It takes time to study and familiarize yourself with the use of code generation plug-ins.
  2. The generated code does not necessarily meet the code specifications. A code compliance check is required after each generation.
  3. After the code is re-generated, the custom code is very likely overwritten. We recommend that you maintain a separate code library, use the DIFF tool to identify code differences, assign values, and then paste the different code.

Method 6: Use Code to Generate Code

That is, write the code by yourself and generate code in your own style. The following takes the MyBatis-based database access code as an example to explain this method.

1. Query Table Information

First, obtain the table and column information required for code generation from the database.

1.1. Query Table Information

The statements for querying table information are as follows:

select t.table_name as 'table name'
, t.table_comment as 'table remarks'
from information_schema.tables t
where t.table_schema = ?
and t.table_type = 'BASE TABLE'
and t.table_name = ?;

The first question mark indicates the value assigned to the database name, and the second question mark indicates the value assigned to the table name.

The table information query result is as follows:

SN. Table name Table remarks
1 org_company Organization company table

1.2. Query Column Information

The statements for querying column information are as follows:

select c.column_name as 'column name'
, c.column_comment as 'column remarks'
, c.data_type as 'data type'
, c.character_maximum_length as 'character length'
, c.numeric_precision as 'numeric precision'
, c.numeric_scale as 'numeric scale'
, c.column_default as ''
, c.is_nullable as 'optional?'
, c.column_key as 'column key name'
from information_schema.columns c
where c.table_schema = ?
and c.table_name = ?
order by c.ordinal_position;

The first question mark indicates the value assigned to the database name, and the second question mark indicates the value assigned to the table name.

The column information query result is as follows:

4

2 Compile and Generate Code

2.1 Compile and Generate the Model Class Code

/** Generate model class file function */
private void generateModelClassFile(File dir, Table table, List<Column> columnList) throws Exception {
    try (PrintWriter writer = new PrintWriter(new File(dir, className + "DO.java"))) {
        String className = getClassName(table.getTableName());
        String classComments = getClassComment(table.getTableComment());
        writer.println("package " + groupName + "." + systemName + ".database;");
        ......
        writer.println("/** " + classComments + "DO class */");
        writer.println("@Getter");
        writer.println("@Setter");
        writer.println("@ToString");
        writer.println("public class " + className + "DO {");
        for (Column column : columnList) {
            String fieldType = getFieldType(column);
            String fieldName = getFieldName(column.getColumnName());
            String fieldComment = getFieldComment(column);
            writer.println("\t/** " + fieldComment + " */");
            writer.println("\tprivate " + fieldType + " " + fieldName + ";");
        }
        writer.println("}");
    }
}

2.2 Compile and Generate the DAO Interface Code

/** Generate DAO interface file function */
private void generateDaoInterfaceFile(File dir, Table table, List<Column> columnList, List<Column> pkColumnList) throws Exception {
    try (PrintWriter writer = new PrintWriter(new File(dir, className + "DAO.java"))) {
        String className = getClassName(table.getTableName());
        String classComments = getClassComment(table.getTableComment());
        writer.println("package " + groupName + "." + systemName + ".database;");
        ......
        writer.println("/** " + classComments + "DAO interface */");
        writer.println("public interface " + className + "DAO {");
        writer.println("\t/** get" + classComments + "function */");
        writer.print("\tpublic " + className + "DO get(");
        boolean isFirst = true;
        for (Column pkColumn : pkColumnList) {
            if (!isFirst) {
                writer.print(", ");
            } else {
                isFirst = false;
            }
            String fieldType = getFieldType(pkColumn);
            String fieldName = getFieldName(pkColumn.getColumnName());
            writer.print("@Param(\"" + fieldName + "\") " + fieldType + " " + fieldName);
        }
        writer.println(");");
        ......
        writer.println("}");
    }
}

2.3 Compile and Generate the DAO Mapper Code

/** Generate DAO mapping file function */
private void generateDaoMapperFile(File dir, Table table, List<Column> columnList, List<Column> pkColumnList) throws Exception {
    try (PrintWriter writer = new PrintWriter(new File(dir, className + "DAO.xml"))) {
        String className = getClassName(table.getTableName());
        String classComments = getClassComment(table.getTableComment());
        writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        ......
        writer.println("<!-- " + classComments + "Mapping -->");
        writer.println("<mapper namespace=\"" + groupName + "." + systemName + ".database." + className + "DAO\">");
        writer.println("\t<!—All field statements -->");
        writer.println("\t<sql id=\"fields\">");
        if (CollectionUtils.isNotEmpty(columnList)) {
            boolean isFirst = true;
            String columnName = getColumnName(pkColumn.getColumnName());
            for (Column column : columnList) {
                if (isFirst) {
                    isFirst = false;
                    writer.println("\t\t" + columnName);
                } else {
                    writer.println("\t\t, " + columnName);
                }
            }
        }
        writer.println("\t</sql>");
        writer.println("\t<!-- get" + classComments + "function statement -->");
        writer.println("\t<select id=\"get\" resultType=\"" + groupName + "." + systemName + ".database." + className + "DO\">");
        writer.println("\t\tselect");
        writer.println("\t\t<include refid=\"fields\"/>");
        writer.println("\t\tfrom " + table.getTableName());
        boolean isFirst = true;
        for (Column pkColumn : pkColumnList) {
            String columnName = getColumnName(pkColumn.getColumnName());
            String fieldName = getFieldName(pkColumn.getColumnName());
            writer.print("\t\t");
            if (isFirst) {
                writer.print("where");
                isFirst = false;
            } else {
                writer.print("and");
            }
            writer.println(" " + columnName + " = #{" + fieldName + "}");
        }
        writer.println("\t</select>");
        writer.println("</mapper>");
    }
}

3 Generate the Relevant Code

3.1 The Generated Model Class Code

/** Organize company DO class */
@Getter
@Setter
@ToString
public class OrgCompanyDO {
    /** company logo */
    private Long id;
    /** company name */
    private String name;
    /** contact address */
    private String address;
    /** company description */
    private String description;
}

3.2 The Generated DAO Interface Code

/** Organize company DAO interface */
public interface OrgCompanyDAO {
    /** Get organization company function */
    public OrgCompanyDO get(@Param("id") Long id);
}

3.3 The Generated DAO Mapper Code

<!—Organize company mapping -->
<mapper namespace="xxx.database.OrgCompanyDAO">
    <!—All field statement -->
    <sql id="fields">
        id
        , name
        , address
        , description
    </sql>
    <!—Get organization company function statement -->
    <select id="get" resultType="xxx.database.OrgCompanyDO">
        select
        <include refid="fields"/>
        from org_company
        where id = #{id}
    </select>
</mapper>

4. Advantages and Disadvantages

Advantages:

  1. The code format can be customized to ensure compliance of the generated code.
  2. The code function can be customized to generate only the desired code.
  3. After the preliminary code precipitation, the code can be used directly later.

Disadvantages:

  1. Data sources need to be studied to ensure that the data required for code generation can be obtained.
  2. It takes a long time to create a data model and compile and generate code.

Ultimate Method: Do Not Stick to a Method Only

Is the ultimate method of coding where you can directly tell the computer what you need and then the computer will automatically generate code? This may become a reality after technologies develop to a certain level in the future. But today, this method is unrealistic. In reality, you cannot "open your mouth to generate code right away", unless you are a boss, product manager, or technical manager.

The ultimate method of coding is to use whatever methods that are appropriate, instead of sticking to a method only. All coding methods listed in this article have their own advantages or disadvantages, and are applicable to different scenarios. Therefore, flexible use of various coding methods is the real ultimate coding method.

Code Standardization

Many of the preceding coding methods require manual compiling of sample code. If your code does not comply with code specifications, it is difficult to find commonalities between code and abstract the sample code that can be used as a standard. If the sample code that functions as a standard does not comply with code specifications, the generated code also does not comply with code specifications, and the noncompliance will be magnified by tens, hundreds, or even thousands of times. Therefore, code standardization is the top priority of coding.

Summary

When thinking about this article, I saw this joke on the Internet: a netizen makes sarcastic comments about the resume of an Alibaba employee, saying that the resume is full of such sentences as "a set of XX methodology is precipitated to empower the XX business". The buzzword "empower" seems very cool. Regardless of the resume, a person who can start with methodology must be worth learning from. Therefore, I would also like to borrow these buzzwords for the title of my article, "Coding Methodology Empowers You and Me."

0 0 0
Share on

Aliware

7 posts | 1 followers

You may also like

Comments