Code complete ch.24 Reconstruction

Source: Internet
Author: User
Tags case statement
What?

In refactoring, Martin Fowler defines it as "changing the internal structure of the software without changing the external behavior of the software to make it easier to understand and modify ".

Why?
  • Myth: a well-managed software project should first develop demand in a systematic manner and define a rigorous list to describe the functions of the program. The design fully complies with the requirements and is done very carefully, so that programmers can write code from start to end in line. It indicates that most of the Code is perfect after being written for the first time, and the test can be left behind. The only time when the code is modified occurs after the new version is delivered for use.
  • Reality: in the initial development stage, code will be substantially evolved. In the initial code writing process, there will be many drastic changes. Even a well-managed project changes about 1/4 of requirements every month, which inevitably leads to code changes-sometimes substantial code changes
Reason for reconstruction
  • Code duplication: whenever you need to modify one place, you have to make the same changes to the other. "copying and pasting is a design paradox"
  • Lengthy Subroutine: There is an inexplicable irritability when we see a subroutine with more than one screen in length.
  • Loop is too long or nested too deep: the code in the loop often has the potential to become a subroutine.
  • Classes with poor cohesion: If a class involves too many tasks, consider splitting it into multiple classes with different responsibilities.
  • Class interfaces fail to provide consistent abstract layers: the result of multi-person maintenance is that a Frankenstein
  • The parameter list of subprograms is too long: no more than 7 gourd dolls
  • The internal modification of a class is often limited to a certain part: If modifications to a class are either in this Part or in that part, there are very few situations where two parts are modified at the same time, this indicates that the class should be split into at least two classes according to the function.
  • Changes lead to the same modification of multiple classes: the code in these classes should be reorganized so that the changes only affect one of the classes.
  • The same modification to the inheritance system: each time you add a derived class to a class, you find that you have to perform the same operation for another class.
  • The data used at the same time is not organized in the form of classes.
  • Member functions use more features of other classes than their own classes: it is time to consider transferring functions to the correct class.
  • A class does nothing: If a class looks non-real, it forwards its functions to other classes and then kills it.
  • A series of subroutines that pass stray data: Check your code and pass the data to a subroutine. Is it just to let the subroutine transfer the data to another subroutine? In this way, the data to be played is called "stray data/tramp Data". You need to check whether the abstract concepts of each subprogram interface are consistent.
  • The man-in-the-middle object has nothing to do: if most of the Code in a class only calls member functions in other classes, consider removing the middleman and directly calling other classes.
  • The relationship between a class and other classes is too close: encapsulation is a powerful tool. If a class knows more about her friends than expected, including a derived class that has an excessive understanding of the content of the base class, do it
  • Improper name of subprograms: longer pain as short pain
  • A derived class only uses a few member functions of the base class. In this case, the derived class is created only because the base class has a function that she needs, instead of a strong logical derivative relationship, you can replace "is-a" with "has-"
  • A large segment of notes for poor code interpretation: Do not write documents for poor code-rewrite the code
  • Using global variables: accessors subprograms are a good alternative
  • The setup code is used before the subroutine call, or the takedown code is used after the call ): the following code is a negative example-it is wrong to specifically instantiate an object to call a subroutine. Why should we use an object as a subroutine parameter?
    Contract contract; contract. setname ("Shanghai catering contract"); contract. setpayrate (5); contract. setapproved (false); addcontract (contract );
  • Some code in the program will be used at some time in the future: over-design is not desirable, and there are too many variables in this kind of speculation; instead of preparing those that do not happen, it is better to try to make the current Code clear and straightforward, so that future programmers (including yourself) will not bother to understand it.
How? Data-level reconstruction/data-level refactorings
  • Replace magic number with a device name constant: neither a number nor a string should appear in the Code as a mysterious number.
  • Make the variable name clearer and pass more information
  • Inline expression: replace an intermediate variable with the expression itself that assigns a value to it (remove too many intermediate variables)
  • Replace expressions with functions
  • Introduce the intermediate variable: Assign the expression value to the intermediate variable (dry! And the above one needs to be considered)
  • Replace a multi-purpose variable with multiple single-purpose variables: If you have a multi-function X that plays multiple roles successively, recruit more actors.
  • Use local variables instead of parameters in local purposes: When you need to change the parameter value, you can use the final keyword in Java to limit that the parameter cannot be modified, however, if an object is input ......
  • Converts a basic data type to a class. If a basic data type requires more operations or additional data, such as money and temperature
  • Convert a group of type codes to a class: See the following example.
    // before refactoringpublic static final int OUTPUT_SCREEN = 10;public static final int OUTPUT_FILE = 20;public static final int OUTPUT_PRINTER = 30;// after refactoringpublic class OutputType {  public static final int SCREEN = 10;  public static final int FILE = 20;  public static final int PRINTER = 30;}
  • Convert a set of type codes into a base class and its derived class. For example, in the preceding example, three Derived classes are available: screen, file, and printer.
  • Convert an array to an object: if an array is being used and different members have different types, you can create an object to replace this array.
  • Encapsulate a collection: Multiple Cluster instances distributed everywhere may cause synchronization problems. Please have your class return a read-only cluster and provide accessors subprograms for adding/deleting members.
  • Use data classes to replace traditional records: Create a class containing record Members
Statement-level refactoring/Statement-level refactorings
  • Break down a Boolean expression: introduce an accurate named intermediate variable to help you understand a Boolean expression.
  • Converts a complex Boolean expression to a Boolean function that is clearly accurate: Improves the readability of complex expressions and facilitates reuse.
  • Duplicate code snippets in different parts of the merge Condition Statement: if the same code exists in the IF/else block, move it from the block to the outside.
  • Use break or return instead of loop control variables: Do not judge the end of a loop by using variables such as stop.
  • Replace conditional statements with polymorphism (especially duplicate case statements): the logic in the case statement can be placed in the inheritance relationship and implemented by using polymorphism call functions.
  • In the nested if-then-else statement, if you know the answer, return immediately: instead of setting a return value, after a series of judgments, return
  • Create and use a null object instead of checking the null value: extract the function for processing the null value from the customer code and put it into the corresponding class.
Subroutine-level reconstruction/routine-level refactorings
  • Extract subroutines or methods: Avoid duplication
  • Concatenate the subprogram code: opposite to the previous one. If the subprogram itself is simple and self-explanatory, use the Code directly.
  • Converts lengthy subprograms into classes to improve code readability
  • Replacing complex algorithms with simple algorithms: writing code that only you can understand is not brilliant.
  • Add/delete Parameters
  • The query operation is independent from the modification operation: One method only does one thing.
  • Merge similar subprograms and differentiate their functions through parameters: if the two subprograms use different constants, you may wish to pass constants as parameters.
  • Split the behavior dependent on the subprogram of the parameter: Do not use the identification space in the parameter to control the subprogram Behavior
  • Passing the entire object rather than a specific member: if multiple specific members of an object are found to be taken out as parameters of a method, why not directly use this object?
  • Passing a specific member rather than the entire object: If you find that an object is created to pass in a method as a parameter, why not let the method directly obtain a specific member of the object as a parameter?
  • Wrap down Transformation Operation: When a subroutine returns an object, it should return the most accurate known object, especially for iterator, Collections
Class implementation refactoring/class implementation refactorings
  • Convert a value object to a reference object: If you find that you are maintaining an extremely large and complex object, you may want to reference it wherever you use it.
  • Converts a referenced object to a value object. If a small simple object is referenced multiple times, you can directly use a value object.
  • Use Data initialization instead of virtual functions: instead of overwriting member functions in multiple Derived classes, it is better for the derived classes to set appropriate constant values during initialization, and then use common code in the base class to process these values.
  • Change the position of a member function or member variable: Move the subroutine/member/constructor to the base class/down to the derived class
  • Extract special code as a derived class: if some code in a class is only useful to some of its instances, put this part of code into the derived class.
  • Combine similar code into the base class: opposite to the previous one
Class interface reconstruction/class interface refactorings
  • Move a member function to another class: Create a new member function in the target class, move the function body to the target class in the original class, and finally call the function of the target class in the original class.
  • Change a class to two: If a class has two completely different functions at the same time
  • Delete class: When he is idle
  • Remove delegation relationships: prevents excessive calls
  • Remove man-in-the-middle: Before a-> B-> C, after a-> C
  • Replacing "is-a" with "has-a": you do not need to expose all member functions of the base class.
  • Replace "is-a" with "has-a": All member functions of the base class must be exposed.
  • Encapsulate exposed member variables: change data members to private, and provide accessors
  • For members that cannot be modified, delete the Set () function.
  • Hide member functions that are not used outside the class
  • Merge the base classes and derived classes with similar implementations
System-level reconstruction/system-level refactorings
  • Create a clear index source for uncontrollable data: organize data into one
  • Change one-way class contact to two-way class contact: two classes need to use each other's functions
  • Change two-way class contact to one-way class contact: in fact, only one class needs to access another class.
  • Use the fatory mode instead of a simple constructor: When you need to create an object based on the type code, or want to use a reference object instead of a value object, you need to use the factory mode.
  • Use the exception mechanism to replace the error code, or replace it with the opposite: Starting from the actual needs, depending on the error handling policy
Rebuilding with Security drops

The knife is sharp.

No one who cut the head of such a knife will be slow.

Whether it's others' headers or their own headers.

  • Save initial code: with mature VCs
  • The pace of reconstruction should be smaller: small steps
  • Only one rebuild at a time: Same as the previous one
  • List all the tasks to be done one by one: maintaining a refactoring list will make you know what has been done and what needs to be done urgently
  • Use multiple checkpoints: when you accidentally mess up a task, you can quickly restore it to the previous working version.
  • Retest: keep a set of excellent test cases
  • Add/delete/modify test cases in real time during refactoring
  • Code Review
  • Adjust the reconstruction method based on the risk level of reconstruction: for example, "refactoring those magic numbers" obviously does not require too much test effort, and does not require code review; when classes, interfaces, and database architecture changes are involved, you must be careful.
Reconstruction strategy
  • Refactor when adding a subroutine
  • Refactoring when adding classes
  • Refactoring when fixing Defects
  • Focus on error-prone modules
  • Focus on complex modules
  • Clearly define the boundary between clean code and poor code, and then let the code cross this boundary

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.