Thirteen, code verification
To ensure the stability and success of the architecture, it is a practical means to verify the architecture using the code. The core of code verification is test, especially unit testing. The basic operational idea of testing is to test priority. It is a very important practice in agile methods, an important guarantee for reconstruction and stabilizing nuclear model.
Code verification in an object-oriented system
Code verification is a way to ensure excellent architecture design, and it is also a measure to avoid like tooth architecture design. In the previous stabilization, the architectural design will eventually be embodied in the form of code, so the formal code is used to verify the architecture is most effective.
Because it is code verification, it is inseparable from writing code, and the code is always related to the specific language, compiling the environment. Here we mainly discuss the Java language used in object-oriented languages, code examples. There are many benefits to architectural design with object-oriented languages:
◆ First, object-oriented language is a better structured language, which can better implement encapsulation, reduce coupling, and allow designers to think at the abstraction level. These factors provide conditions for excellent architecture design.
◆ Secondly, object-oriented languages can allow designers to focus only on the frame code without care for specific implementation code. Of course, this is not to say that the language of non-object-oriented objects can't do this, but it is better for object-oriented language.
◆ Finally, object-oriented languages can be used well. This means that designers can use the original knowledge, the original software system to solve new problems.
In addition, use Java language, you can also get more benefits. Java language is a language-oriented language. We know that the Java language itself does not support multiple integration, all Java classes are inherited from the Object class. In this way, once a inheritance system is determined to be changed. In order to achieve the flexibility of multiple inheritance, Java introduces interface mechanisms, using interfaces and uses abstract classes, there is nothing different, a specific class can implement multiple interfaces, and the client can use the interface type, as below such:
List employees = new vctor ();
If you need to change the Vctor to LinkedList, other code does not need to do more modifications in addition to the creation code above. In addition to this interface, Vctor, this specific class also implements Cloneable, Collection, Randomaccess, Serializable. This shows that in addition to the List interface, we can also access the VECTOR class through the interface listed above. Therefore, the interface inheritance can become a supplementary means of inheritance and play a flexible role. At the same time, it avoids multiple inheritance complexity. However, only empty methods can be defined in the interface, which is a defect in the interface. Therefore, in actual programming, interfaces and abstract classes are usually used together. We see the Collection interface and the AbstractCollection abstraction class that implements the Collection interface in Java's Java.util package is an example of this. You can inherit from the AbstractCollection abstraction class (or its subclass) so you can use the default code implementation in AbstractCollection, because AbstractCollection implements the Collection interface, your class also implements the Collection interface; if you don't need to use The code in AbstractCollection, you can write a class yourself to implement the Collection interface (this example is unlikely in this example, because the reuse of the tool class has been very good). There are many similar examples in Java. Java language design is not the focus of our discussion. More in-depth discussions can refer to special books, here we don't make too much introduction. It took some space to discuss some simple preparation knowledge for object-oriented design and interface design. These knowledge will become the basis for code verification.
Interface and architecture
The interface here is not the concept of Interface in Java, which is a generalized interface, which is manifested in the Java language. The method of public method or interface is manifested. There is also similar but not exactly the same manifestations in the COM system or J2EE system. For a system architecture, the most important fact is to define these interfaces. Through these interfaces, link the system's class, and provide services to the user through the interface to connect external systems (eg, databases, legacy systems, etc.). Therefore, in order to verify the architecture, we are transformed into verification requirements for the interface.
The basic idea for verifying the interface is to ensure the testability of the interface. To ensure that the interface has talent, you must first analyze the responsibilities of class and classes. There are several principles here that can improve the testability of the interface.
1, package principle
The implementation details of the interface should be packaged inside the class. For the user of the class, he only needs to know the public method issued by the class without knowing the implementation details. In this way, the corresponding test code can be written according to the common method of the class, as long as these test code, the design is successful. For architectures, the testability of the class is the foundation, but the light guarantees that this is not enough.
2, the principle of the smallest responsibilities
How many functions to achieve in a class (interface) have always been an incredible problem. But a class implemented function should be as compact as possible, only some of the closely related features are processed in a class, and a method should only do one thing. In this case, the test code of the class will also be concentrated, ensuring the testability of the class. Recalling the example we discuss in hierarchical modes, implementing class as different users, which is also an embodiment of the minimum principle.
3, minimum interface principle
For methods that are used to users, you need to be careful. In general, the release method should be as few as possible. Since the publication of the public may be frequently used by customers, there is a problem in design, or it needs to be improved to improve design, which will affect existing methods. Therefore, these effects need to be minimized. On the other hand, some lightweight common methods should be combined into a single method. This reduces the degree of coupling of the user and the system, and the specific approach can be used in appearance mode, and the service entrust mode can also be used. About this discussion, you can refer to the hierarchical mode. Less interfaces can alleviate the workload of the test and make the test work more concentrated. 4, minimum coupling principle
The minimum coupling principle is that your design and other types of interactions should be as few as possible. If a class and a large number of coupling are found, new classes can be introduced to weaken this coupling. In design patterns, intermediary mode and appearance mode are applications such as such applications. For testing, especially unit testing, the most ideal situation is that the class is a simple class, and there is no relationship with other classes. But this kind of reality is very small, so we can do as much as possible to reduce the coupling of test classes and other classes. In this way, the test code is relatively simple, and the type of test code is relatively small when modified.
5, hierarchical principle
The hierarchical principle is the promotion of the package principle. A system often has a variety of responsibilities, such as the code that is responsible for dealing with the database, and the code that is dealing with the user. These codes can be achieved in different parts of the software architecture depending on the functionality of the function. To develop tonable guarantees of the class into testability of the architecture. Just use the hierarchical principle to the system, and write test code at the level level. For a detailed discussion of layers, see Terrace Mode.
If your design is unable to meet the above principles, the architecture can be improved by reconstruction. With regard to the topics of the reconstruction, you can refer to the Martin Fowler's Reconstruction Book and Joshua Kerievsky 's Reconstruction to Mode.
If we are in depth, what is the meaning of a verifiable architecture? This is the concept of test driver and automation test mentioned in the next section.
Test drive
The concept of test driver may be unfamiliar. The same concept in RUP is test priority design, while in XP, in XP as test-first programming. In fact, we have worked unconsciously in our daily work, but to improve the test driver, it is necessary to attribute to agile methods. The basic idea of test driver is to take into account the design (or write) test code before designing (or coding), so that the test work is not only testing, but it becomes a specification of design (or code). Martin Fowler called "Specification By Example"
In the field of agile test. One approach is to fully express demand as test code. In this way, the demand work of software designers is no longer how to write demand to capture the needs of users, but how to write tests to capture users. There is a significant benefit to do this. The most deadly code in the software design is that the code does not meet the demand in the test work, and there are many reasons why this happens, but the result is very terrible, it will lead to a lot of rework. The demand is organized as the form of test code, and the final code can be able to meet the requirements as long as it can be tested. Of course, this certain is precise, that is, the test code is able to fully and accurately describe the needs. It is not easy to do this. We can imagine that when you need to analyze the user, there is basically no code, and even the design is not. At this time, you have to write test code, which is hard to do. This requires the designer to prepare the test code, the overall architecture of the system has become a bamboo on the chest. Therefore, although this technology has a beautiful future, it is still far mature. Although we have no way to completely use the above technologies, it is entirely possible to borrow our thoughts.
First, test the idea of test code replacement, because the test code is not ambiguous, it can be very accurately descriptive requirements (because the code level is the finest level), and closely combines the architecture. Therefore, from the demand analysis phase, we should maintain the testability of the demand document as much as possible. One of the possible ways is to use CRC technology. CRC technology can help designers analyze key classes in demand, and find out the relationship between classes and classes. Similar techniques in RUP. The business entity represents some physical classes in the field, defines the responsibilities and relationships of business entities, and can help improve design tonicity. No matter which method, its idea is to use analysis technology to find key factors in the business sector, and refine.
Second, the test driver believes that the test is not only tested, but more importantly, the test has become a contract. Used to guide design and test. In this regard, Bertrand Meyer has already proposed the concept of Design by Contract. From the smallest unit of software design, this contract is actually an interface between the manufacturer and the consumer of the class.
Finally, all relevant personnel in the software development team can clearly understand the test code, so they are helpful for architectural design, implementation, and improvement. Here is a question about the responsibility of the tester. In general, we believe that the main responsibility of the tester is to find out the mistake, the problem is that the test staff spends a lot of time to find out some developers should not be committed. For modern software, testing is undoubtedly a very important piece, but if the test staff is mostly furnished by a large number of errors that can be avoided, then the quality and cost of the software will be lacking. A excellent tester should focus on the availability of software, including whether it meets the demand, whether it meets the specifications, and the design is defect, and the performance is not good enough. In addition to finding defects (note that we use defects here, not wrong), the testers should also find out the causes of defects, and give a correct opinion.
Therefore, a better approach is to ask developers to test software code levels. Therefore, give the architecture test code and require implementation of the code to improve the effective means of improving software quality. After understanding the idea of testing the driver, let's answer the problem at the end of the next section. The maximum benefit of the verifiable architecture is to create an continuous improved architecture through an automated test. In the reconstruction mode, we understand the significance of the reconstruction of the architecture, and ensure the testability of the architecture, and establish a test network (discussed in the next section), the architecture can be successfully reconstructed. . We know that the basic meaning of the reconstruction is to adjust the internal structure under prerequisites that do not affect the external behavior of the code or architecture. However, once the code is adjusted, it is difficult to ensure that the incarnation of its external behavior is difficult. Therefore, the automation test is realized by the test-driven ideas, and the automation test is an equivalent of the external behavior of the architecture. Regardless of how the architecture evolves, as long as the test can pass, the external behavior of the architecture has not changed. Test for interface
As with the forebel, the concept of interface here is still a broad interface. We hope that the architecture can maintain the stability of external behavior when reconstructing. But it is not easy to do this. The published interface should ensure stability, and designers need to have extensive design experience and field experience. The principle of the minimum interface mentioned above, one of which is the case, the more interfaces, the more troubles bringing in the future. Therefore, when we design the architecture, when designing, we should start from designing their interfaces, rather than thinking about concrete implementation. This is a major difference between object-oriented ideas and process ideas.
Here, we need to review the way to find constant factors from changes in stabilizing this mode. The method described in the stabilization mode is equally applicable to this mode. Only the interface is stable, the test script can be stable and test automation can be carried out smoothly. Package the factor of the change is the main idea to maintain the stable test script. The factors of change and the degree of packaging are different depending on the environment. For a project, the database is generally fixed, then the code of data access is already capable of meeting changes as long as the code can be concentrated in a fixed location. But for a product, you need to access the data access layer (or the Or mapping layer), which is designed to dynamically replace the Connection for different databases.
Test network
The last concept of this chapter is the concept of test network. If stringent is developed in software development according to test priority. The software will also generate a test network consisting of a large number of test scripts. Why is it a test network? The test script wrapped the software, and the power of any place in the software, the test network will immediately reflect it. This is like a spider web, which can quickly and effectively manage requirements, design changes.
The script of the test network is primarily made by unit testing. Therefore, in addition to writing programs, the developer's work needs to be knitted and repaired. The meaning of weaving is to write test code before writing code, and the meaning of the repair is to modify the test script when the interface is changed due to software changes. Additional work seems to be an increase in the workload of developers. But in our daily practice, we found that the facts are just the opposite. Although the developers will lead to the decline in development due to the construction of the test network, but to the medium term for the development process, the test network will save the software change will be offset. Initial input. Moreover, with the familiarity and identity of the test priority, the cost of building the test network will continue to decline, and the advantage will be more and more obvious:
◆ It is easy to detect the error code, and the developers have removed their worries, so that they can constantly develop new features. In addition, it is the basis for the creation of the code day.
◆ Save a lot of time for testers, enabling testers to concentrate concentrate on more beneficial places.
In addition, there is an additional cost that constitutes the test network. If the development team is not familiar with the object-oriented language, then the change in the test network in the interface instability increases its construction cost. to sum up
As can be seen from the above discussion, the architecture and code are unfolded, and the architecture is unable to be called a good architecture. This is determined by the target of the architecture. The final goal of the architecture is to be executable, and the architecture provides structural guidance for the code. Therefore, using code to verify the architecture is an effective practice. To achieve this practice is not an easy thing, we need to consider the code-level architecture related knowledge (we discuss the knowledge in the object-oriented language, but similar ideas can also be found in other languages), and use They design service for architecture.