Refactoring is an operation that must be done to write code. It should also be something that programmers are willing to practice. Whether it is logical implementation or design process, or even the entire layered structure, we may face and implement reconstruction. This article will not tell you what refactoring is, how to perform beautiful refactoring, and so on. I just want to share some feelings with you and discuss some questions. In the last two weeks, I have been restructuring a sub-business framework of our team. In many cases, I feel very painful, so I came to this article.
Where is the root cause of the entire body?
When I open the solution and view the code, we will find many problems, such as redundant code and Low-performance logic implementation. But when I start to transform, the subconscious tells me that the whole task cannot be moved, and the scope of the task is too wide. To change a small place, make corresponding adjustments to the next string, which is certainly not what I want to see. A wide range of adjustments will directly affect the system stability, bring potential risks, and increase the burden on the test team; in terms of version control, there will be a huge difference between the online and offline versions. What can we use to ensure that an almost all-new set of code replaces the online system during version update? Because many problems can be exposed only in the most real environment.
The modification cost is huge, because we expect to modify only a small piece of code. A wide range of code adjustments are also accompanied by unit test code adjustments. If the test team re-uses the test cases, the effort is hard to imagine.
What I want to do is refactor rather than rewrite it. What causes this phenomenon?
The entire solution has a relatively complete hierarchy, namely DAO layer, entity layer, and business logic layer. The entity layer also defines data entities and business entities separately. However, when implementing the business, we did not implement effective isolation and division of code responsibilities.
Many codes call DAO directly when processing business logic, and then use the returned data to organize business entities. When our business entities need to be divided into two or more layers by domain, the results will become worse, because we need to input the underlying business entity to output the upper-layer entity. When you complete a complete set of operations in an ordered workflow, you may feel a sense of accomplishment. The whole process is seamless and perfect. However, when we try to change some of the content, the nightmare begins. Physical changes will inevitably lead to logical changes, but such changes have a chain reaction.
The process of business implementation is often the process of entity conversion between different layers. Therefore, in the process of implementation, it is impossible to receive good results only when we consider removing dependencies. Starting from the responsibility of business logic, A clear business layer can be divided, and a combination of entity transformations can be considered to achieve good results.
An independent domain layer is particularly important.
The implementation of various classic MVC architectures is often misunderstood, and it is assumed that the implementation is perfect. In fact, the focus of a business framework is not to add, delete, modify, and query. I prefer to separate DAO from the business framework (I did the same in the end ), the entire system should provide uniform DAO services, and the sub-business framework should focus on business implementation.
When we try to separate a whole set of business entities, we think we have done a good job of business understanding, but this is the idea of seeing no trees in the forest. In some systems, domain implementations only account for a very small proportion of the total code, but their importance is often the opposite. When we choose to mix domain code with other code, it means that our layered structure is also chaotic.
"The standard architecture model is used to achieve loose association with the upper layer. All Domain-related code is concentrated at one layer and separated from the code at the user interface layer, application layer, and infrastructure layer. Domain objects can focus on expressing domain models without having to relate to their own display, storage, and management of application tasks. In this way, the model is developed in a rich and clear way ".
After clarifying the entire domain model, I think it is reasonable to choose an appropriate mode to solve the layered problem.
Do not start when you do not fully understand your business and fields
During the reconstruction process, we found that many business entities have different definitions. Many concepts only expand data entities. The results are different from the logical relationships between data entities.
If you do not fully understand the logic of data retrieval, improper data access methods such as circular access to the database may easily occur when organizing business entities.
If the establishment and division of the entire domain model are incorrect, we can still implement the required functions. However, restructuring such code is definitely a re-engineering.
Now it seems that, when we are in a hurry to achieve the function, it will pose a hidden danger for future maintenance and upgrade.
When we want to abstract public data retrieval and business logic implementation from each sub-project into a base class, interface, Helper, or Service, I found that developers of different sub-projects have very different understandings of their businesses and fields, so there are great differences in implementation methods and entity definitions. At this time, we noticed that the logic of organizational entities was not separated separately, and the extraction work encountered difficulties. Maybe we can separate the proxies and use the Adapter to adapt to the original entity organization logic. Maybe we should abolish the unreasonable entity definition, which also means that the corresponding implementation logic is abolished.
If I choose to replace unreasonable entities with correct object definitions, there will be a huge challenge. Maybe the logic will be adjusted from data retrieval to final logic. Of course, the reason for the comprehensive adjustment is that we have not achieved good isolation.
Confused, facing a Method of thousands of lines
This is an intolerable situation. The implementation of the entire sub-business is done in a few generous ways. There are countless "Region" and "End Region" in each method ". In this case, don't talk about separation and design. At the very least, when you are using "Region" and "End Region", you should realize that a method can be separated here.
Large methods have many drawbacks. It has poor maintainability and readability. It is not integrated with the hierarchical structure of the system and cannot be used for effective unit tests.
Of course, refactoring of large methods is not as complicated as the Code itself, if its logic is clear enough. However, if a programmer with clear thinking can write such code, how can he reconstruct the code, A major problem is the reuse of local variables in different logics. Of course, the more important issue is to clarify the clues.
It makes no sense to complain. What is the reason for such a method? First, developers do not have a good understanding of the structure and purpose of the business framework. Second, they do not have a good understanding of the basic idea of program design. Third, they do not have a clear understanding of the business logic itself.
For the reconstruction of such implementation, in addition to starting from the business point of view, what is the best way? Is it re-engineering?
Rebuild at any time
If a piece of code does not feel appropriate and cannot be reconstructed in time, the entire solution may become a garbage dump. In the future, developers will take a reasonable view of the spam code. In particular, new members can only imitate what others are doing.
From the test-driven development philosophy, program development is an iterative process that is constantly restructured. Many people think of refactoring as a major event and are afraid of it as soon as they hear it, especially the test team. Of course, we cannot deny that improper refactoring will cause a lot of trouble to the test team.
Centralized refactoring is an extremely wrong idea. Don't try to wait until some development tasks are over, so you have time to concentrate on refactoring the code. When the system is relatively stable, the cost of restructuring may be unacceptable to the entire team.
The reconstruction of the layered architecture should be the initial period of time when the architecture was established, and the optimization should be made continuously. After a project is completed, it is unacceptable to adjust the overall structure.
Reconstruction should avoid over-design
The final point of attention is that refactoring should be carried out around a moderate goal, and the cost should be taken into consideration. It does not mean that the more pattern applications, the better. On the contrary, during the reconstruction process, you must always consider whether to make simple answers complicated.
At present, there is no such problem in the code I restructured, so I won't be so embarrassed here.
Having said so much, I still want to hear your opinions and feelings, how to conduct effective refactoring, and how to avoid many reconstruction obstacles at the very beginning of programming?