Article structure index: ========================================================== ================================
Preface
Modifying code is different from refactoring.
Basic Premise of reconstruction: Understanding the original design intent
Desire and direction of refactoring: Making existing code implementation easier to expand
Decision on restructuring: do you want to proceed or give up?
Before reconstruction: absorbing the essence of original design ideas
Before reconstruction: Find out which parts should be reconstructed
Misunderstanding of reconstruction: avoiding excessive reconstruction and Design
Start restructuring: first, let's look at your design.
Reconstruction started: Do not write it by yourself first, to see if there are any ready-made components available?
Reconstruction process: continuous improvement in fun
Reconstruction process: continuous testcase
Verify
What exactly has been practiced in restructuring?========================================================== ================================
Refactoring is an "eternal topic". As long as development continues, refactoring will always be with us.However, "refactoring" is not an easy task. Instead of reading this article refactoring: improving the design of existing code, it will be restructured. Over the past six months, major technical sites have been hyping SOA, Ajax, and agility, but few have mentioned "refactoring ". In fact, there are still very few experienced architects and senior R & D personnel in the software industry in China, and "restructuring" is the basic work that these two types of technicians must practice. However, there are not many opportunities for development in China to "refactor. Many people are rooted in complicated changes to the project's needs, and have no time to take care of "looking back and organizing your thoughts and code ". Especially in the project implementation of "platform flooding", a large number of implementers are considering "how to implement functions under the existing platform and framework ", seldom consider "whether there is room for improvement in the code structure ". I have been dealing with product R & D for most of the past few years, so I am lucky to belong to a small group of people who "have a chance to practice restructuring. Of course, we are even more unfortunate than our friends at TW. After all, there are not many companies that can be "agile" to TW. Compared with the above, it is more than enough. Naturally, I have some experience. Some time ago, I played another "refactoring", which is to refactor a command line processing class and talk about some experiences.
Modifying code is different from refactoring.Code modification is very different from refactoring. Maybe you are not very familiar with a component, but through debug and track, you can easily "edit code" or "Fix bug ". However, this is still far from restructuring. For example, I have been to the CDC for almost a year. I have experienced two "maintenance version" Development and the ongoing "major version" development. The previous two "maintenance versions" only fix bugs, and there is not much reference material. Basically, they can only rely on their own debug and track methods to analyze, track, locate bugs, and fix them. During that time, we were all mocking ourselves. "reading code basically depends on guesses, and modifying code basically depends on ignorance ". At that time, it was quite difficult to locate bugs and modify bugs in the old Code, and there was no possibility of "refactoring. -- But we have successfully modified many bugs, which also means that a lot of code has been modified. For us, the only benefit is to understand the old code structure and indirectly absorb the design ideas of foreign senior architecture. However, during the development of two "maintenance versions", we do not have any "refactoring" behavior.
Basic Premise of reconstruction: Understanding the original design intentThe basic premise of refactoring is that you must be familiar with the old code structure ". Of course, if you can understand the original design ideas, it is easier to refactor the existing code structure. But in many cases, we can only "speculate" the original author's design intent by reading the code. For example, a command line class that is being restructured recently. This command line class is used to maintain more than a dozen complex operations such as application upload and deploy. The general class method structure is as follows (the real analogy is more complex ):
(Main function) Main (string []) (processing task function) task (string []) (executing task ):. action () (execute a task ):. deploy (application, xinode) (executes a task ):. exit (string, Int, INT) (initialization ):. init () (resolution parameter ):. parse (string []) (print help ):. usage () (print a task help ):. usagedeploy () (print the help of a task) ...... (verify the input parameter ):. validate () |
Obviously, this old code class carries this very obvious "process-oriented" thinking model. Of course, this is a common problem of many "command line" classes. When a command line class was initially built, there were fewer tasks and fewer lines of code and methods,
Complex Design may affect code building efficiency.In this way, the "streamline" design may be easier to implement and maintain. In order to better illustrate the problem, I drew a simple "Mind Map" to interpret the original author's design intent (this design intent is only analyzed based on the Code ). If you can understand the basic design intent of the author in the old code, you can basically develop and refactor it. Of course, there may be some small points that are omitted when you read the code (after all, there is no complete design document), but this does not have a great impact on "refactoring, grasp some of the key design intent, and others can experience and learn in the reconstruction process.
Desire and direction of refactoring: Making existing code implementation easier to expandIf you are a developer who embraces agile, "refactoring" will certainly be closely focused on your thinking. As a developer, there should also be a desire for reconstruction at all times. In fact, the above command line class is very mature. After several years of supplement, we have to support more than a dozen tasks. Replace the name of the command line class with applicationmanage. Many years later, this class became a very "bloated" class, a class with more than 2000 rows.
In this way, each task has its own specific parameters: applicationmanager-upload-domain AAA-archive user · applicationmanager-deploy-domain AAA-app appname · if you need to add a new task at this time, for example, we need to achieve the following effect: applicationmanager-
Newtask-Domain AAA-file tesfile... at this time, you must modify the code of applicationmanage in many places: Add code in different places according to the original code logic and structure: I need to add resolution to several new parameters when parsing input parameters. I need to add resolution of new parameters in the verification area. I need to add support code for new usage. I need to add support code for new task processing to support a new task, the code is neither difficult nor complex, but I have to modify it back and forth in many aspects of a class. You know, this is a class of 2000 rows. -- This is the "bad taste of code ". Yes. At this time, when you are faced with such an "unbearable" code modification, you need to develop a "refactoring" desire. We don't have to look for a lot of high-sounding reasons for "refactoring". This one is enough:
We feel that a better implementation structure can make it easier for us to expand..
Decision on restructuring: do you want to proceed or give up?When you want to refactor, will you be able to refactor? This is a problem that requires time cost and risk estimation. After several years of development, applicationmanager has become quite stable. However, feature freeze does not allow time to be changed. Even if the old code is "bloated", the stability and correctness tested by time cannot be overturned. There is only one ending: the old code can only be used to add a new task. Is the reconstruction plan so forced to give up? Of course, you should not give up. There are not many opportunities that can be used to cultivate reconstruction. "the prey is in sight. How can we give up easily ?" Yes, I cannot submit the "refactoring" code to SVN, But I Can Do It In sandbox. "Refactoring doesn't have to be in real project code ". In fact, refactoring in real project code is a "very dangerous" behavior, unless you have enough time and complete design ideas, or your project manager has approved a wide range of code modifications. Otherwise, it is best to practice and pre-develop your ideas in "sandbox. The customer does not care about the implementation of the code, but only about "functions, efficiency, and stability ". Some people will come up and add "scalability". Yes, customers are also concerned about "scalability", but the "scalability" that customers are concerned with is only peripheral expansion, the real code structure of many internal implementations is "transparent to the customer", and the customer is not concerned about the internal code implementation that is meaningless to the customer. Remember this: no one can stop you from putting your thoughts and practices in "sandbox", except yourself. -- Of course, you must coordinate your time and work. At nine o'clock, when sitting in front of a computer at home, who can stop us from practicing our ideas in "sandbox? Inspiration sometimes comes from the silence of the night! -- Do not stay up late. The fate of Huawei's family Brother Hu deserves the "Vigilance" of all developers ".
Before reconstruction: absorbing the essence of original design ideasRefactoring does not mean that the old code is completely discarded. In many cases, the old code is clearly labeled as "historical": they were originally designed to meet the current needs and to quickly implement certain functions at that time. At that time, the design was correct, but with the subsequent expansion of functional requirements, the structure gradually became bloated, making it increasingly difficult to maintain. The above applicationmanager is like this. However, for any component, "existence means its value". There must be some design ideas that can withstand the test of history. First, we should find out these "design ideas that should be absorbed ". Occasionally, some developers complain about the old code: refactoring is better than rewriting. -- There may be "old code with no value at all", but the chances are too small.
As a developer, we should reconstruct it based on the idea of "absorbing the essence of old design ideas as much as possible.The applicationmanager command line class has some good design ideas: (1) the basic processing process is correct: parsing, verification, initialization, task execution, and usage printing. (2) put forward the idea of "task. A command line class is considered to be composed of many tasks. In terms of code implementation, there are also some good "code" that can be used for reference, so we will not describe it here.
Before reconstruction: Find out which parts should be reconstructed
Refactoring has an impact on the old code: some code needs to be abandoned, transformed, and reorganized. We mentioned in the previous section that we should absorb the "essence" of the Old Code. In this section, we should "strip the bad code ". The applicationmanager command line class has some good design ideas and some unfortunate structures. (1) Although the concept of a task is separated, Parameter Parsing is shared. Each task has its own specific parameters. Some parameters are common, while some parameters are private. How is the old command line class implemented?
Private string mdomain; private string Muser; private string mpassword; private string mfile; private string Mapp; private string marchive; // omitted |
Yes. In the old command line class, all parameters are defined as the properties of the command line class. If you need to add a task, and the parameters associated with the task must add some attributes. (2) Each time you add a parameter definition, you need to add a "If else" code snippet to parse the parameter. In fact, task Parameter Parsing can be abstracted. Let's take a look at the code snippet of the old command line parsing these parameters:
For (;) {If (stack. isempty () {break;} If (Arg. equalsignorecase ("-? ") | Arg. equalsignorecase ("-help") {printhelp = true; If (stack. isempty () Exit (null, usage, succeeded);} else if (processcommand (ARG) | processbatch (ARG) {If (printhelp) Exit (null, maction, succeeded);} else if (Arg. equalsignorecase ("-app") {} else if (Arg. equalsignorecase ("-file") {}// omitted} |
Obviously, after a task is added or a parameter is added, You have to modify the code snippet again here. (3) Each task is composed of many parameters. Every parameter has commonalities, so you can perform abstract verification ". The combined verification of each parameter constitutes an abstract verification of a task. However, how is the old command line class implemented?
Private void validate () {If (maction = upload) {If (marchive = NULL) {// omitted} else if (maction = deploy) {If (MAPP = NULL & mconfigurl = NULL & marchiveurl = NULL) {// omitted} |
(4) Every time you add a task, you have to add a new usage method and write some "cumbersome" Help materials. However, these usage values can be fixed by the parameters held by the task. (5) · (there are other things that I think are inappropriate. I will not describe them here, it is the goal you should first reconstruct. Of course, at this time, you may have some new feature that you want to implement, so it can also be included in your refactoring goal.
Misunderstanding of reconstruction: avoiding excessive reconstruction and DesignMany people, when restructuring, accidentally entered the "complicated" misunderstanding. The search for "scalability" will inevitably complicate the supported code structure, but it cannot be blindly designed because of some "Possible scalability", so that the reconstruction goal can be simply enlarged. This excessive refactoring and design will lead to a "Reconstruction journey on the road" such as the applicationmanager command line class, which has been broken down into: Task + parameters. However, in the initial design intent and implementation, tasks are "Parallel. Deploy and upload are two tasks, which are totally parallel. However, in reality, the complexity of command line processing can easily be seen in the following situations: applicationmanager-flatten-export-xxx applicationmanager-flatten-revert-xxx, the flatten task generates "Two Independent Tasks ". Is it necessary to add a "subtask" concept to the task? -- This idea has no errors. However, for the "start reconstruction" phase, excessive "consideration" is a "secret. Excessive consideration and design can only make you more confused, but it does not have any advantages for restructuring. Let's take a look at the reconstruction parts above. In addition, to analyze the old tasks, the parameters of only one or two tasks are slightly more complex. That is to say, this "subtask" design has little value. Even in this case, the simple "If else" can be easily processed in the task processing class.
Start restructuring: first, let's look at your design.Is it necessary to design "refactoring? Of course, you need to design it, but you don't need to use any UML tool to draw the class digoal. This "formal" design is only used for archiving, Which is easy for future generations to understand. Sometimes it is also used for discussions with others. The standard class digoal is easy for most people to accept. However, if you only need to reconstruct and use it yourself, simply think about it in your mind, or simply draw on paper. Next, we will plot the Reconstruction Design for applicationmanager into a thinking graph. Let's take an example. (In fact, when I was refactoring, I simply drew a picture on paper ). In this way, you can abstract the basic elements of the command line class: option, taskoptions, and task.
Reconstruction started: Do not write it by yourself first, to see if there are any ready-made components available?Here, there may be a group of complaints: why didn't we find open-source components at the beginning? If you look for open-source components directly, there will be no "practice". Besides, the existing open-source components are not necessarily suitable for you. However, when you want to know what you want and how you want to do it, you can find "existing components" and get more: (1) if there are similar open-source components, you can measure it in a more comprehensive manner, and it is easier to understand the design ideas of open-source components. (2) If there is no such idea, you should start to refactor open-source components related to command line parsing, the most famous is the Apache CLI component. Currently, the release version is 1.1. I analyzed the CLI design and drew a line of thought, as shown in the following figure (note that only some of the main relationships are covered, while others are not covered, such as helpformatter ): after analyzing the CLI, you will understand that this is not suitable for our command line class: (1) CLI is only used to parse the command line parameters (2) CLI does not have the taskoption concept, all options are equal. (3) because CLI only focuses on command line parsing, It is very complicated to parse option. However, such a complicated parsing method is not suitable for our command line operations. I like simpler parsing, for example, optiongroup. (4) Our command line class needs to be completed: Parameter Parsing and task execution, not just parsing. However, the CLI is something worth learning and absorbing: The options object inspired me, and this is what taskoptions lacks: taskoptions can use the options object to manage options.
Reconstruction process: continuous improvement in funRefactoring is a pleasant process, and of course it is also a pleasure. Reconstruction itself should be an "iterative" process, which approaches the target structure step by step. However, there will be some minor improvements in the reconstruction process. Do not overthink about changing your original ideas ". If you find that you are too far away from the original design during the refactoring process, we suggest you stop coding and spend some time organizing your thoughts to consider the overall design. However, small improvements are almost inevitable. For example, when initially implementing the option object, I only considered several attributes: name, whether it has a value, value, description, and whether it must exist. However, when the usage printing function is implemented in the future, there is a problem: the output option help information is always unordered. Of course, I try to sort it by the option name, however, this does not seem to be a "business-based" sorting. Finally, I have to add an "order" attribute for option to allow the customer to manually set the output sequence of which parameters. There are still many examples of such improvement in the reconstruction process, because it is relatively trivial and will not be described here. As a matter of fact, these only need to go through several refactoring processes, and will go through several code improvements during this "Journey.
Reconstruction process: continuous testcase
VerifyThis is an old topic. The reconstruction process is accompanied by the testcase verification process. Continuous testcase can ensure that your implementation is in the "correct" direction. "Iteration" and "testcase" are always mutually dependent.
What exactly has been practiced in restructuring?What exactly did one reconstruct itself cultivate? Just to make the structure of a component better? Oh, this is just the harvest of seeing, and there are many gains that you can feel when you don't see yourself. (1) the reconstruction process is to make the previous conception design more perfect. After a reconstruction is completed, your own "design capability" will inevitably improve. Of course, such improvement may not bring a qualitative leap in a short time. However, with the accumulation of time, the number of "refactoring" practices increases, and the design components become more and more complex. One day, you can easily grasp a complex component or product. (2) do not read this design pattern to master "excellent class relationship design ". Books only introduce others' experiences, but whether they can be truly absorbed requires repeated attempts and accumulation in "restructuring. After all, "refactoring" is a bridge connecting the old code structure and the new code structure. The evolution of this process is actually a step-by-step process of practicing various "pattern Applications. (3) Do you still remember the analysis model? It is actually explaining some "implementation modes of scenarios". How do you think these models come out? -- In fact, this is a summary of the experiences accumulated, evolved, and reconstructed by those masters. -- For example, the command line class we just restructured is actually a scenario implementation. Of course, during the "refactoring" process, you will also occasionally experience some "code skills" attempts to make your code more concise, efficient, and well-structured. -- This will also cultivate the code skills. Reconstruction: what exactly has been practiced? The above is just some of my experiences. I think, in the face of restructuring, the reader's own practices can bring more gains to you.
Statement: This is the first csnd blog. For more information, see the original article address and author. Thank you.
==========================================
Author information:
Hu Great Wall (silver fox 999)
Tibco China R & D center, infrastructure team
Home: http://www.javafox.org
Blog: http://blog.csdn.net/james999