This is the third day of my participation in the August More text Challenge. For details, see:August is more challenging

preface

After a year of development, I’m no longer a rookie (although technically it still feels like one), I’m beginning to understand the importance of refactoring (the pain of reading existing code), and I recently read the book Refactoring – Improving the Design of existing code and taking notes.

Introduction to Code Refactoring

What is refactoring

Making changes to code to improve the internal structure of the program without changing the external behavior of the code.

Essentially, refactoring is about improving the design of code after it has been written.

Two points about refactoring

The goal of refactoring is to make the software code easier to understand and modify, but to keep the observable external behavior of the software as unchanged as possible. (Performance tuning, on the other hand, usually does not change the behavior of a component, only its internal structure. Performance tuning often makes the code harder to understand, but has to be done for performance.)

Refactoring tips

  • Refactoring takes small steps, using unit tests to make sure things are right and reduce the chance of mistakes.

  • Refactoring.

  • Try to get rid of temporary variables, which tend to cause problems -P45

  • It is best not to use a switch statement based on the properties of another object. If you have to use it, you should use it on the object’s own data, not on someone else’s data (to make the coupling between objects and classes less)

  • State mode and strategy mode, depending on your needs at the moment.

Refactoring technique

Extract Method

Move a Method from one class to another

Replace Conditional with Polymorphism

Self Encapsulate Field, use set, and GET for assignments, even in constructors.

Replace Type Code with State/Strategy Replace Type Code with State/Strategy

Two hats developed using refactoring techniques

When you add new features, you shouldn’t change existing code, just add new features, test them, and measure your progress.

When refactoring, do not add functionality, only improve the results of the program, do not add any tests at this point (unless you find something previously missing), and change tests only when absolutely necessary (to handle interface changes).

Refactoring principle

Refactoring should happen anytime, anywhere, not for refactoring’s sake. You refactor to ask what else you want to do, and refactoring helps you do those things well.

The law of the third order

Just do something the first time you want to do it

The second time you want to do something similar, you will be disgusted, but you can do it anyway.

The third time you do something similar, you refactor

When refactoring

Refactor when adding functionality

Refactoring motivation:

  • Help yourself understand the changed code

  • The design of the code doesn’t make it easy to add the features you need. Refactoring is a fast and smooth process, and once the refactoring is complete, new features are added faster and more smoothly

  1. Refactor when fixing errors

    Refactoring is used during debugging, mostly to make the code more readable. Use refactoring to deepen understanding and help find bugs.

    If you receive an error report and the bug is not immediately visible, this is a signal that you need to refactor

  2. Refactor when reviewing code

Layer of indirection

Disadvantages of the indirection layer

Refactoring often involves introducing more layers of indirection, breaking large objects into smaller objects and large functions into smaller functions. But what you should recognize is that the level of indirection is a double-edged sword. Every time you introduce a layer of indirection, the cost is that you have to manage something more.

The value of the indirection layer

  • Allow logical sharing
  • Explain intent and implementation separately
  • Isolate changes
  • Encapsulation conditional logic

How to treat the indirection layer in refactoring:

Refactoring is about both introducing valuable layers of indirection and removing worthless “parasitic layers of indirection.” (Layer of parasitic indirection: it’s supposed to be called in multiple places to show polymorphism, but it’s actually only used in one place)

Code that needs refactoring

  1. Difficult to read, difficult to revise.
  2. The logic is repetitive and difficult to modify.
  3. Adding a new behavior requires modifying existing code and is difficult to modify.
  4. With complex conditional logic that is difficult to modify.

Refactoring goals:

  1. Easy to read.
  2. The same logic occurs only once.
  3. The new changes do not compromise existing behavior.
  4. Express conditional logic as simply as possible.

Refactoring challenges

Database – A separation layer solves the problem of tight coupling between the application and the underlying database structure

Modify an interface – How do I modify a published interface

When changing a function name, if all the callers of the function are under the developer’s control, there is no problem in changing the function name in a timely manner. Even public functions.

However, interface modification becomes a problem when the interface is used by code that can’t be found, found, and cannot be modified. These interfaces are called publish interfaces.

Published interfaces (such as Jar packages for the Android system layer; Some of the interfaces of the company’s custom system; In multi-module development, you cannot manipulate other people’s code, but they have already called your published interface.

  • General solution (keep the old interface) :

    Let the old interface call the new interface. And mark the old interface as deprecated

  • Do not publish public interfaces unless necessary

Modify Interface – Added exceptions

If you add an exception to the throw clause in a Java method, the compiler will not let it pass unless the user code is accustomed to it.

To solve this problem:

It is generally possible to define an exception base class for the entire package, like java.sql’s SQLException, and ensure that all public functions declare this exception only in their throws clause. After that, you can define subclasses as much as you want in the package without affecting the caller, who always knows the more general exception base class.

Design changes that are difficult to accomplish through refactoring

When not to Refactor

  1. When the code is too messy, refactoring towers are not as easy as rewriting one, and you should forgo refactoring
  2. Avoid refactoring when a project is close to a deadline

Refactoring and design

Refactoring and design complement each other.

With refactoring, you still need to think about potential changes at design time, and you still need to think about flexible solutions, but you don’t have to implement them one by one. As long as you think it’s easy to refactor the current simple solution into a complex solution, you just need to implement the current simple solution.

Refactoring and Performance

Except for real-time systems where performance is critical, the secret to writing fast software is to write debuggable software first, and then adjust it to gain speed.