At the beginningCodeThere is a high enthusiasm for reuse. At that time, I always hoped that the functions, classes, and modules I wrote could be reused and could solve all the problems beautifully. But it is often counterproductive. design changes, demand changes, and unexpected situations ultimately destroy your code completely. Sometimes different versions of a simple function may appear, such as sendmessage, sendmessage2, sendmessageex ...... Explain the subtle differences in the annotations. The reuse plan eventually went bankrupt. After the attack, we went to another extreme: Using copy-paste to solve the problem. Don't care about the reusability of code, give up on the beauty, and go toward the complete implementation. Various types of bad smell are constantly appearing in the Code. They are crazy about copying and pasting and then slightly modifying it. Once changed, modify it everywhere. Faced with demand changes, product upgrades, messy code, outdated documents, it is really a painful experience.
Can code reuse be achieved? How can it be reused?
Code reuse requires high design quality.
Designing and writing reusable code is not easy. Simply put, we need to establish a simple relationship between the requirement, concept, and final implementation [the aspects blog]. It is best to have a direct embodiment of a concept or requirement in implementation. For example, to design a company's management system with employees, design an employee class to indicate the concept of employee. If an employee has a salary, add a salery attribute to the employee class to indicate the employee's salary. The optimal relationship between demand and implementation should be, that is, a requirement corresponds to a unique implementation. In this way, there is only one implementation to be modified when the demand changes. In this case, code reuse is also the best, and the same function is completed with only one piece of code.
"Requirement: Implementation =" is an optimal state. To achieve this state, you must first have a clear understanding of the requirement and try to eliminate the ambiguity of the requirement. This is the basis. Secondly, we should observe some basic principles in design to avoid unreasonable dependencies. It is difficult to reach this value. Generally, it will be weighed based on the specific situation.
Different levels of abstraction should be used at different stages of the design, so the problem cannot be expressed too early. The time for concrete is too early, which often means that one requirement corresponds to multiple implementations. Some designers tend to focus less on abstraction and are eager to implement functions. The design method is often like this: requirement investigation, proposing software solutions based on users' needs, and designing databases based on the solutions, design the fields and relationships of database tables. After the database design is complete, the business logic is clearly organized, and then simpleProgramDesign, and then start coding. Many of the codes are direct operations on database tables. The business description is usually as follows: press a button to open a screen, query a data from a data table and display it on the interface. Press a menu to modify a field in the data table ...... This is the direct operation from the UI to the dB, and there is no abstract level. Such a design has limited adaptability to changes in requirements.
Demand changes often occur during software development and maintenance, and demand changes are often at different abstraction levels. For example, a monitoring system for equipment manages various electrical equipment, such as motors, transformers, and compressors. The user puts forward the following requirements:
1. Each time the device data is collected, when the voltage of the device exceeds the rated voltage of 50%, the power supply of the device is automatically cut off.
2. When the current of the transformer is greater than 10% of the rated value, a red light should be displayed on the interface.
These two requirements are at different abstraction levels. Requirement 1 is for a more abstract "device", and requirement 2 is for a more specific "transformer ". These two different abstract layers should be reflected in the design and coding.
If the user later changed the demand: "When the voltage of the device exceeds 50% of the rated voltage for a certain period of time, the power supply will be cut off. Otherwise, the power supply will not be cut off. After 2 seconds, if you try to connect the power source again and find that the voltage still exceeds, the connection will be disconnected." Such a requirement change should be implemented at the abstract level of "device. Without this abstract level, this change is troublesome.
Code reuse within a project and between projects
When talking about code reuse, the original idea was to design a perfect module to solve all the immediate and long-term problems once and for all. In fact, there are limits on reuse. A product or project must solve a specific problem. The solution to many problems is different from the specific environment. In general, our goal should be to write code that can be reused within the project. Code can be reused within the project, which should be the goal pursued by the designer. Once this goal is achieved, it means that the product has a stable structure and enters an efficient development stage. Reusable code can reduce the occurrence of bugs and the impact of demand changes.
As the customer's business continues to change, the demand will inevitably change. At this time, the design should be reconstructed in a timely manner to adapt to new requirements. The original code can be reused to the maximum extent. Many business modules do not have to be rewritten, so the pressure on new versions will be reduced.
There are many forms of code reuse between projects. You can copy and paste a function to a new project, or introduce some files to a new project. This is not the best form of reuse. Code reuse between projects generally uses "packages" as the minimum unit. The Creator publishes a package. The user determines whether to use the package as needed. The format can be static concatenation or dynamic calling. When the maintainer of the package finds a bug or adds a new feature, the package will be re-released after modification. Users decide whether to upgrade based on their own needs. There is always only one "package" for maintenance. This is the best form of reuse.
"It is better to write one by myself to reuse others ." Really?
We often have this experience: to reuse others' code, we need to learn a lot. Query Information, read documents, read examples, and even read code. Sometimes the learning time may be longer than writing code with the same function. As a result, many people do not like to reuse code at work, but tend to write one by themselves. "It is better to write one by myself to reuse others ." Is that true?
Consider this question first: whether the "write yourself" time simply refers to the encoding time or the complete development time. Encoding is only a stage of development. Writing one by yourself may not be difficult or take too much time. But we need to test, modify bugs, and improve the documentation ...... A series of work has been done, which generally takes longer than the time to reuse the code.
There is another problem: writing one by yourself makes it difficult to achieve good reusability. Next time I encountered a similar problem, I had to write another question. It is better to study how to use other modules now.
From the management perspective, as the project staff change, these "self-written" modules will become increasingly difficult to maintain. Some mature modules have well-developed documents, so it is easier to find relevant materials and to learn and use them more easily. You must use the best tools you can buy and reuse the most suitable code.