Refactoring-improving the design of existing code: Writing 22 Code crimes (3)

Source: Internet
Author: User


1 Duplicated Code repeated Code

The same program structure appears in different places:

If you see the same program structure in more than one location, you can be sure: try to combine them into one, and the program will become better. The most common "repeated code" means that two functions in a class contain the same expressions. Another common case is that two sibling child classes contain the same expressions.
1) the two functions of the same class contain the same expression. In this case, you can use the Extract Method to Extract repeated code, then let the two locations call the extracted code.
2) two sibling child classes contain the same expression. You only need to use the extract method (extraction function) for both classes ), then, the extracted function uses the pull up method to push it into the superclass. If the code is similar but not identical, you must use extract.
Method (the extract function separates the similarity and difference to form a separate function. Then you may find that you can use form template method to obtain a template method design pattern. If some functions use different algorithms to do the same thing, you can select one of them clearly and use substitute
Algorithm replaces the algorithms of other functions.
If two irrelevant classes have repeated code, you should consider using extract class to extract the repeated code into an independent class, then use the new class in another class. However, the function where repeated code is located may only belong to a class, and the other class can only call it, or this function may belong to the third class, the other two classes should reference the third class. You must decide where the function is most suitable and ensure that it will not appear anywhere else after it is placed.

2 Long Method too Long Function

In principle, the number of lines of code in a function should not exceed 100:

We follow the principle that every time we feel that we need to annotate something, we need to write it into an independent function, it is named after its purpose (rather than implementation method.

In 90%, to reduce the number of functions, you only need to use the extract method (extract function) to find the appropriate part of the function that fits together and extract them to form a new function.

If a function contains a large number of parameters and temporary variables, they will constitute an obstacle to your function extraction. You can often use replace temp with query (replace temporary variables with queries) to remove these temporary elements. Introduce
Parameter Object (introducing a Parameter Object) and Preserve Whole Object (keeping the Object complete) can simplify long Parameter columns.
If so, there are still too many temporary variables and parameters, Replace Method with Method Object should be used (Replace function Object ). How can I determine which code to extract? A good trick is to look for comments. They usually point out the semantic distance between code usage and implementation techniques. If there is a line of comment in front of the Code, it reminds you: you can replace this code with a function, and you can name this function based on the comment. Even if there is only one line of code, if it needs to be annotated, it is worth extracting it into an independent function.

Conditional expressions and loops are often extracted signals. You can use Decompose Conditional to process Conditional expressions. As for the loop, we should extract the loop and its code into an independent function. (All benefits of the indirect layer-interpretation, sharing, and selection-are supported by small functions)

3 Large Class Excessive Class

Class is not responsible for surpassing the responsibilities of this class, that is, the single principle mentioned above:

If you want to use a single class to do too many things, too many instance variables will often appear in it. In this way, the repeated Code will come one after another.
Use Extract Class to Extract several variables to the new Class. When refining a class, you should select variables related to each other in the class and put them together. Several variables in a class usually have the same prefix or suffix, which means they have the opportunity to be extracted into a component. If this component is suitable as a subclass, you can use Extract
Subclass (extract Subclass ).
Sometimes classes do not use all instance variables at all times. Extract Class and Extract Subclass can be used multiple times)
If a Class has too much code, it is also suitable for Extract Class and Extract Subclass ). Tip: first determine how the client uses them, and then use the Extract Interface to Extract an Interface for each method of use. It helps you understand how to break down this class.
For a GUI class, you may need to move data and behavior to an independent domain object. You may need to retain some duplicate data on both sides and keep the synchronization on both sides. Duplicate Observed Data (copying "monitored Data") tells you to do so.

4. Long Parameter List too Long Parameter Column

Too long parameters are hard to understand and maintain:

Too long parameters are hard to understand and cause inconsistency and are not easy to use. And once you need more data, You have to modify it. If you pass an object to a function, most modifications are unnecessary. Exception: do not create a dependency between the called object and a large object.

If one request is sent to an existing object to Replace one Parameter, Replace Parameter with Methods (Replace the Parameter with a function) is used ). Here, the "existing object" may be a field in the class to which the function belongs, or it may be another parameter. You can also use the Preserve Whole Object to collect a bunch of data from the same Object and replace them with this Object. If some data lacks a reasonable object ownership, you can use
Introduce Parameter Object (introducing Parameter objects) creates a Parameter Object for them.
Important exception: If you obviously do not want to create a dependency between the "called object" and "Large Object. At this time, it is reasonable to split the data from the object as a separate parameter. However, pay attention to the cost. If the parameter columns are too long or change too frequently, you need to reconsider your dependency structure.

5. Divergent Change (relative Focus)

A lot of code is required to modify a place, because the modified Code is scattered everywhere:

If you cannot make modifications at a specific point when the system needs to be modified, you should be aware that the code is too tightly coupled:

For example, a man is a "focal cognitive" and a woman is a "divergent cognitive". To put it simply, a focal cognitive style is to aggregate a large area into a point. On the contrary, a divergent style expands a point into a large area.

Men can find out the commonalities of Several Problems and try to solve them. Men aim to solve the problem. A woman can split a problem into several directions and never want to solve the problem. Women aim to tell the problem.

If a class often changes in different directions for different reasons, a Divergent Change occurs. At this time, it may be better to divide this object into two, so that each object can be modified only because of one change. All the corresponding changes to a change outside a certain field should only occur in a single class, and all the content in this new class should reflect this change. To this end, we should find all the changes caused by a specific reason and then Extract them into another Class using Extract Class.

6. Shotgun Surgery elastic Modification

Only one simple modification requires changing multiple classes. That is, we need to modify the code to spread around:

Shotgun Surgery should be modified in a pop-up manner (only one simple modification requires changing multiple classes. That is to say, the code we need to modify is spread around, so it is not only difficult to find them, but also easy to forget an important modification. ) Separating multiple classes is a major responsibility of the Code. There may be a lack of classes that fully understand their responsibilities (and a large number of modifications should be done for this class ). In addition, this bad taste may also be caused by excessive removal of divergent changes.

Find a class responsible for these changes. This may be an existing class, or you may need to use the application extraction class to create a new class. Use the Move Field and the Move Method
Method) to place the function in the selected class. If the unselected Class is simple enough, you can use the Inline Class to remove the Class.

7. Feature Envy attachment plot

Class method should go to the place where:

A function is more interested in a class than in its own class. The common focus is data. A function calls almost half a dozen value functions from another object to calculate a value. At this time, a moving Method (the moving function) is used to Move it to the place where it should be. Sometimes only a part of functions suffer from this attachment, and Extract is used at this time.
The Method (extraction function) extracts this part into an independent function, and then uses the Move Method to take it to its dream home.

A function usually uses several classes. Where should it be placed? Our principle is: to determine which class has the data most used by this function, and then put this function and that data together.

8. Data Clumps Data dashboard

A large number of data items are to be added:

You can often see three or four identical data items in many places: the same fields in two classes and the same parameters in many function signatures. The data that is always tied together should have their own objects. First, find out where the data appears in the form of fields and extract them into an independent object using extract class. Then focus on the function signature and use introduce
Parameter object (introduce parameter object) or preserve whole object (keep object complete) for it to lose weight. The direct advantage of doing so is that many parameter columns can be shortened and function calls can be simplified. You don't have to worry about data clumps. You only need to use a part of the fields of the new object. It is worth replacing 2 (or more) fields with the new object.
A good way to judge is to delete one of the numerous data items. In doing so, is other data meaningless? If they are no longer meaningful, this is a clear signal: You should create a new object for them.

9. Basic Primitive Obsession type paranoia

You prefer to use basic types instead of small objects:

An extremely valuable thing about objects is that they blur (or even break) The boundaries between basic data and large classes. You can easily compile small classes that are of the same built-in (basic) type as the language.
New users of object technology generally do not want to use small objects in small tasks, such as money classes that combine values and currencies, and a Range class consisting of a starting value and an ending value. You can use replace data value withobject (replace the data value with the object) to replace the original data value with the object. If the data value to be replaced is a type code that does not affect the behavior, replace the type code with class (replace the type code with class) to replace it. If you have a conditional expression related to the type code, you can use replace type code with subclass (replace the type code with a subclass) or
Replace type code with State/Strategy
(Replace type codes with status/policy.
If you have a set of fields that should always be put together, you can use Extract Class (Extract Class ). If you see the basic data type in the Parameter column, try Introduce Parameter Object (Introduce the Parameter Object ). If you find that you are selecting data from an Array, you can use Replace Array with Object (Replace Array with Object ).

10. Switch Statement)

The switch statement is repeated:

One of the most obvious features of object-oriented programs is that they use less switch or (case) statements. Essentially, the problem with switch statements lies in repetition. You often find that switch statements are distributed in different locations. If you want to add a new case clause for it, you must locate all switch statements and modify them. The concept of polymorphism in the object-oriented model can provide an elegant solution.

Most of the time, you should consider replacing the switch statement with polymorphism. The problem is, where does polymorphism occur? Switch statements are often selected based on the type code. You need "functions or classes related to this type code", so use Extract
The Method (extraction function) extracts the switch statement into an independent function, and then moves it to the class that requires polymorphism using the Move Method. In this case, you must determine whether to use Replace Type Code with Subclass (Replace Type Code with Subclass) or Replace Type Code with State/Strategy (Replace Type Code with status/policy ). Once this inheritance structure is completed, you can use

Replace Conditional with Polymorphism (Replace Conditional expressions with Polymorphism.
If you only have some selection cases in a single function and do not want to modify them, polymorphism is unnecessary. In this case, Replace Parameter with Explicit Methods (Replace the Parameter with a definite function) can be used ). If one of your selection conditions is null, try Introduce Null Object (Introduce Null Object ).

11. Parallel Inheritance Hierarchies balanced Inheritance System

The parallel inheritance system is actually a special case of Shotgun Surgery:

In this case, each time you add one subclass to a class, you must also add one subclass to the other class. If you find that the class name prefix of an inheritance system is exactly the same as the class name prefix of another inheritance system, it smells bad.

The general strategy to eliminate this repeatability is to allow an inherited system instance to reference another inherited system instance. If you continue to use the Move Method and Move Field, you can cancel the inheritance system of the reference end.

12. Lazy Class (redundant Class) if the income of a Class is not worth the value, it should disappear: if some subclass does not have enough work, try Collapse Hierarch (fold inheritance system ). Corresponding to almost useless components, should use Inline
Class to deal with them. 13. Speculative Generality)

Do not use the following classes if they are not used:

If a certain abstract class does not have much function, use Collapse Hierarch (fold inheritance system ). Unnecessary delegation can be removed using Inline Class (condensed Class. If some parameters of the function are not used, you can Remove the Parameter ). If the function name has redundant abstractions, you should implement Rename for it.
Method (function name)

If the only user of a function or class is a test case, this is a bad smell. Speculative Generality ). If such functions or classes exist, delete them together with their test cases. However, if they are used to help test cases detect legitimate functions, they cannot be deleted.


14. Temporary Field (confusing Temporary value range)

Temporary attributes of objects are often confusing:

Sometimes you will see an object where an instance variable is set only for a specific situation. Such code is hard to understand, because you usually think that an object needs all its variables at all times. If the variable is not used, you can guess that the purpose you set will drive you crazy.

Use extract class to create a home for these variables, and then put all the Code related to these variables into this new home, maybe you can also use introduce Null Object (introduce Null Object) to create a null object when the variable is invalid, so as to avoid writing conditional code.
If there is a complex algorithm in the class and several variables are required, temporary fields with confusing bad taste may appear. Because the implementer does not want to pass a long string of parameters, he puts these parameters into the field. However, these fields are valid only when the algorithm is used. In other cases, they are confusing. In this case, you can use extract class to extract these variables and their related functions into an independent class. The new extracted object is a function object.

15. Message Chains (over-coupled Message Chains)

Object A requests object B, object B requests Object C ...:

If you see that the user requests another object from one object, then the latter requests another object, and then requests another object ...... This is the message chain. In actual code, you may see a long string of getthis () or a long string of temporary variables. This means that the customer code will be closely coupled with the navigation in the search process. Once the relationship between objects changes, the client must modify the relationship accordingly.

This should be used
Hide Delegate (Hide delegation relationships ). You can perform this reconstruction in different locations of the message chain. Theoretically, any object in the message chain can be reconstructed, but in this way, a series of objects are often converted into Middle Man (Man-in-the-Middle ). Generally, a better choice is: first observe what the final object obtained by the message chain is used to see if it can be
Extract Method extracts the code using this object into an independent function, and then pushes this function into the message chain using the Move Method.

16. Middle Man (intermediate transfer Person)

Excessive use of delegation:

One of the basic features of an object is encapsulation: hiding its internal details from the external world. Encapsulation is often accompanied by delegation. For example, if you ask your supervisor if he has time to attend a meeting, he will "delegate" The message to his notebook before he can answer you. You do not need to know whether the supervisor uses a traditional album or an electronic album or secretary to record his appointment.

However, delegated permissions may be excessively used. You may see that half of the functions of a class are delegated to other classes, which means excessive use. In this case, you should use Remove Middle Man to directly deal with the objects in charge. You can use
Inline Method (Inline Function) puts them into the caller. If these middlemen have other behaviors, you can use Replace Delegation with Inheritance (Replace Delegation with Inheritance) to convert them into subclass of the actual responsibility object, so that you can expand the behavior of the original object, there is no need to carry so many delegate actions.

17. Inappropriate Intimacy (relationship)

Two classes are too close:

Sometimes you will see two classes that are too close and spend too much time exploring the private components of each other. You can use the Move Method and Move Field to draw a line between them. You can also see if you can use Change Bidirectional Association to Unidirectional (Change two-way Association to one-way Association) to break one class from another. Use Extract if the two classes are really keen.
Class (refining Class) extracts the two things in common to a safe place so that they can use this new Class openly. Alternatively, you can try to use Hide Delegate (to Hide the Delegate relationship) to let another class share their thoughts.

Inheritance often leads to excessive intimacy, because subclass's understanding of superclasses always exceeds the latter's subjective desire. If you think it is time to let the child live alone, use Replace Inheritance with Delegation (Replace Inheritance with Delegation) to leave the Inheritance relationship.

18. Alternative Classes with Different Interfaces (similar class)

Two functions do the same thing:

If two functions do the same thing but have different signatures, use Rename Method to Rename them based on their purposes. But this is often not enough, please use it repeatedly
The Move Method moves some actions into the class until the two are consistent. If you need to repeat the code to complete this operation, you may be able to use Extract Superclass to refine the super class ).

19. The reuse of Incomplete Library Class (imperfect Library Class) is often regarded as the ultimate goal of objects. However, the significance of reuse is often overestimated: Most objects only need to be enough. However, it is undeniable that many programming technologies are built on libraries. Database Class builders do not use the capabilities of crowdsourced security testing, so they cannot be blamed. The trouble is that the Library is often not well constructed, and it is often impossible for us to modify the classes so that they can do what we want to do. Does this mean that technologies that have passed practical tests are useless today?
Fortunately, we have two tools dedicated to this situation. If you only want to modify one or two functions of the class library, you can use Introduce Foreign Method (to Introduce an additional function). If you want to add a large number of additional actions, you must use
Introduce Local Extension (introducing Local extensions ). 20. Data Class (pure Data Class)

The so-called Data Class refers to the fact that they own some fields and the functions used to access these fields. In addition, they have nothing to do. Such classes are just data containers that do not speak, and they must be controlled by other classes excessively. These classes may have public fields in the early stage, so you should use Encapsulated Field to encapsulate them immediately before others notice them. If these classes contain the fields of the container class, you should check whether they have been properly Encapsulated; if not, use Encapsulated Collection
Encapsulate them. For fields that should not be modified by other classes, use Remove Setting Method (to Remove the Setting function ).

Then, find out where these value/value functions are used by other classes. Try
The Move Method (shift function) moves the call behavior to the Data Class. If this function cannot be moved, use the Extract Method (Extract function) to generate a movable function. Soon, you will be able to use the Hide Method (hidden function) to Hide these values/set value functions.

21 Refused Bequest (rejected gifts)

Subclass should inherit the functions and data of superclasses. But what if they don't want to or do not need inheritance? They get all the gifts, but they just pick a few of them to play.

According to the traditional saying, this means that the design of the inheritance system is incorrect. You need to create a new sibling class for this subclass, and use the push down Method (function down) and push down field (field down) again to push all unused functions to that sibling. In this way, the superclass only hold things shared by all sub-classes. You often hear the suggestion that all super classes should be abstract. Now that you use the derogatory term "traditional saying", you can guess that we do not recommend that you do this. At least we do not recommend that you do this every time. We inherit and use inheritance to reuse some behaviors and find that they can be well applied to daily work. This is also a bad taste. We do not deny it, but the smell is usually not strong. Therefore, if Refused
Bequest causes confusions and problems. Follow the traditional advice.

But you don't have to think you have to do that every time. In, the bad taste is very light and it is worth ignoring. If the sub-classes reuse the superclass behavior, but do not want to support the superclass interface, the bad taste of the Refused Bequest will become strong. We don't mind rejecting the implementation of the inherited superclass, but we don't agree if we refuse to inherit the interfaces of the superclass. However, even if you do not want to inherit interfaces, do not modify the Inheritance system randomly. The application uses Replace Inheritance with Delegation (replacing Inheritance with Delegation) to achieve the goal.

22 Comments (too many Comments)

We mention annotations here because they are often used as deodorant. This is often the case where you see a piece of code with long comments and find that these comments exist because the code is very bad. Annotations help us find the bad taste in the code. After finding the bad taste, we should first remove the bad taste with a variety of reconstruction methods. After the completion, we often find that the comment has become redundant, because the Code has clearly explained everything.
If you need annotations to explain a piece of code, try the Extract Method (Extract function). If the function has been extracted, but you still need annotations to explain its behavior, try Rename Method (function name change). If you need to comment out the required specifications of some systems, try Introduce Assertion (Introduce assertions ).


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.