preface

The term “refactoring” is familiar to most engineers. In fact, most people just “listen more than they do.” Not many people actually refactor their code, and even fewer make continuous refactoring a part of their development.

On the one hand, refactoring code requires much more of an engineer’s ability than simply writing code. Refactoring requires you to be able to see bad smells or design flaws in your code, and to be able to solve them with reasonable and skillful theoretical knowledge of design ideas, principles, patterns, and programming specifications.

Why, on the other hand, many engineers to refactor, what refactoring, when and how to reconstruct the related problems, such as understanding is not deep, to reconstruct no systematic, overall understanding, in the face of a pile of bad code, without the guidance of a reconstruction techniques, change can only think of what to what, can not comprehensively improve the code quality.

Reconstruction mainly includes the following aspects:

A general introduction to refactoring, including why, what, when and how; Methods for ensuring error-free refactoring, with emphasis on unit testing and testability of code; Different scale refactoring, focusing on large-scale high-level refactoring (such as system, module, code structure, class to class interaction, etc.) and small-scale low-level refactoring (refactoring of classes, functions, variables, etc.). Purpose of refactoring: Why? How does the guru describe refactoring? Software design guru Martin Fowler defines refactoring this way: “Refactoring is an improvement of the internal structure of software in order to make it easier to understand and less costly to modify without changing its visible behavior.”

In fact, many books cite this definition when talking about refactoring. There is a point worth emphasizing in this definition: “Refactoring does not change externally visible behavior.” Refactoring can be understood as the use of design ideas, principles, patterns, programming norms and other theories to optimize the code, modify the design deficiencies and improve the quality of the code on the premise of keeping the function unchanged.

With a brief look at the definition of refactoring, let’s focus on why code is refactoring.

First of all, refactoring is an extremely effective way to keep your code quality from becoming hopelessly corrupt. Projects evolve, and code keeps piling up. Without someone to take responsibility for the quality of your code, it tends to evolve in a more chaotic direction. When the confusion reaches a certain level, quantitative change leads to qualitative change, and the maintenance cost of the project is already higher than the cost of redeveloping a new set of code, and no one can do it again.

Second, great code or architecture can’t be completely designed from the start, just as great companies and products are iterative. We can’t meet 100% of our future needs, nor do we have the energy, time, or resources to pay for the distant future, so refactoring code is inevitable as systems evolve.

Finally, refactoring is an effective way to avoid over-design. In the process of maintaining the code, when we really encounter problems, we can effectively avoid investing too much time in the early stage to do excessive design, so as to achieve the target.

In addition, refactoring is important for the growth of an engineer’s skills.

From the definition of refactoring, refactoring is actually an application of the classical design ideas, design principles, design patterns and programming specifications that we have learned. Refactoring is actually a good scenario to apply this theoretical knowledge to practice, to practice our ability to skillfully use this theoretical knowledge. On top of that, you may feel like you’re not growing much by building business logic, but you can feel a sense of accomplishment by rebuilding a bad piece of code into a better one.

In addition, refactoring ability is also an effective measure of an engineer’s code ability. “Junior engineers maintain the code, senior engineers design the code, and senior engineers refactor the code.” This sentence means that junior engineers fix bugs and add feature code under the existing code framework. Senior engineers design code structure and build code framework from scratch; Senior engineers are responsible for code quality, and need to find problems in the code, reconstruct the code, and always ensure that the code quality is in a controllable state.

What to refactor: What to refactor?

According to the scale of refactoring, we can be generally divided into large-scale high-level refactoring (hereinafter referred to as “large refactoring”) and small-scale low-level refactoring (hereinafter referred to as “small refactoring”).

Large-scale refactoring refers to the refactoring of top-level code design, including system, module, code structure, and the relationship between classes. The refactoring means include layering, modularization, decoupling, abstract reusable components and so on. The tools for this kind of refactoring are the design ideas, principles, and patterns we’ve studied. This kind of refactoring involves many code changes and has a large impact, so it is difficult and time-consuming, and the risk of introducing bugs is relatively high.

Minor refactoring refers to the refactoring of code details, mainly for classes, functions, variables and other code-level refactoring, such as canonical naming, canonical annotation, elimination of oversized classes or functions, extraction of duplicate code, and so on. Small refactorings take more advantage of coding specifications that we will discuss later. This kind of refactoring requires more concentrated modifications, which are relatively simple, highly operable, time-consuming and less likely to introduce bugs. All you need to do is master the various coding specifications.

When to refactor: When?

Now that we’ve figured out why to refactor, what to refactor, let’s look at, when to refactor? Is the code rotten enough to refactor? Of course not. Because when the code is really bad to the point of “development efficiency is low, hire a lot of people, work overtime every day, not enough work, bugs happen frequently online, leaders get angry, middle management can’t do anything, engineers complain constantly, it is difficult to find bugs”, basically refactoring can’t solve the problem.

Personally, I am opposed to the behavior of not paying attention to the quality of the code, piling up rotten code, and reconstructing it or even rewriting it when it can’t be maintained. Sometimes there’s so much code in a project that it’s hard to do a thorough refactoring, and you end up with a “monster”, which is even more troublesome! Therefore, it is unrealistic to expect centralized refactoring to solve all problems once the code has broken enough that we must explore a sustainable and evolutionary approach.

So, the refactoring strategy I particularly advocate is continuous refactoring. When you have nothing else to do, take a look at the code in your project that isn’t written well enough to be optimized, and take the initiative to refactor it. Or, when modifying or adding a feature code, you can easily refactor a bad design that doesn’t conform to the code specification. In short, just as unit testing and Code Review are part of development, it would be good for the project and for us if we could make continuous refactoring a part of development as a development habit.

Although we say the ability to refactor is important, the awareness of continuous refactoring is even more important. Keep code quality and refactoring in perspective. Technology updates, requirements change, people move, code quality will always decline, code will always be imperfect, and refactoring will continue. Constant refactoring is the only way to avoid over-design in the early stages of development and the degradation of quality during code maintenance. The person who scolds someone when they see a flaw in their code, or who spends a lot of time coming up with a perfect design, is often the one who doesn’t have a good sense of code quality and a constant sense of refactoring.

Refactoring methods: And how?

As we mentioned earlier, refactoring can be broadly divided into large refactoring and small refactoring, depending on the size of the refactoring. We need to make a distinction between these two types of refactoring at different scales.

For large refactorings, there will be a lot of modules and code involved. If the project code quality is poor and the coupling is serious, it will often affect the whole process. The refactorings that you thought could be completed in a day will become more and more changes and more and more changes will become more and more chaotic, and you will not be able to handle it in a week or two. New business development clashed with refactoring, and eventually fell by the way, reverting all changes, and frustrated with piling up bad code again.

When undertaking a major refactoring, it is important to plan the refactoring well in advance and proceed methodically in stages. Each stage completes a small part of the code refactoring, and then submits, tests and runs. After finding no problems, the next stage of the refactoring is continued to ensure that the code in the code repository is always in a runnable and logically correct state. At each stage, we need to control the scope of the code affected by the refactoring, consider how to accommodate older code logic, and write compatible transition code if necessary. In this way, each stage of the refactoring will not take too long (ideally in a single day) and will not conflict with new feature development.

Large-scale, high-level refactoring must be organized, planned, and discreet, with experienced, business-savvy senior colleagues leading the charge. Small-scale low-level refactorings can be done whenever you want and have the time because of their small scope of impact and short change time. In fact, in addition to finding low-level quality problems manually, there are a number of mature static code analysis tools (CheckStyle, FindBugs, PMD, for example) that automatically find problems in your code and then optimize for them.

As for the reconstruction, senior engineers and project leaders should take the responsibility to reconstruct the code whenever they have no problem, so as to keep the quality of the code in a good state. Otherwise, once the “broken window effect” occurs, one person piles bad code in, and more people pile worse code in. After all, the cost of piling bad code into a project is too low. However, the best way to maintain code quality is to create a technical climate that drives people to focus on code quality and constantly refactor code.

The key to review

Today’s presentation gives you a proper, holistic view of refactoring and builds awareness of ongoing refactoring. This is probably more important than teaching you some refactoring skills, because many technical problems themselves are not solved by technology alone, but by awareness and awareness.

1. Purpose of refactoring: Why?

In the case of a project, refactoring keeps code quality under control and not beyond redemption. On an individual level, refactoring exercises one’s coding skills and is a very rewarding experience. It is the training ground where we learn classical design ideas, principles, patterns, programming specifications and other theoretical knowledge.

2. Refactoring objects: Refactoring what?

According to the scale of reconstruction, we can roughly divide the reconstruction into large-scale high-level reconstruction and small-scale low-level reconstruction. Large-scale high-level refactoring includes layering, modularizing, decoupling, teasing out the interactions between classes, abstracting and reusing components, and so on. This part of the work is more abstract, more top-level design ideas, principles, patterns. Small-scale low-level refactorings include normal naming, annotation, correction of excessive function parameters, elimination of oversized classes, extraction of duplicate code and other programming details, mainly for class and function level refactorings. Small-scale low-level refactoring relies more on theoretical knowledge of coding specifications.

3. When to refactor: When?

Over and over again, I emphasize the importance of building a sense of continuous refactoring as an essential part of daily development, rather than waiting until the code has a major problem and then refactoring.

4. Refactoring methods: How?

Large-scale, high-level refactoring is difficult and requires organization, planning, and step-by-step sprinting to keep the code in a working state. Small-scale low-level refactorings can be done anywhere if you want and have the time because of their small scope of impact and short change time.

[javawu.com/archives/25…]