Before discussing the nlayerapp project, let's first learn (or repeat) the hierarchical/multi-layer architecture and application system design principles. Many of my friends will think that these are old-fashioned content. As long as they are software practitioners, they will be very familiar with this content. But is that true? I will sort out this part here. On the one hand, it will lay the foundation for introducing nlayerapp, on the other hand, it is hoped to take this opportunity to sum up these theoretical things and hope that readers and friends can read them carefully, after all, let's learn more.
It should be noted that, starting from this chapter, most theoretical things are sourced from the nlayerapp 《Architecture guide bookAs a matter of fact, the English version of guideline has not yet been completed. I will extract some chapters for translation and induction. If you are interested, please go directlyMicrosoftnalyerapp.codeplex.comDownload the English version on the site.
Layers and tiers
It is very important to distinguish layers from tiers. From the perspective of Chinese translation, the two are both "layers", so we often confuse these two concepts. The term layer is more about the logical differentiation of system components or functions. It does not mean to distribute components to different regions or servers. Tier indicates physical deployment of system components and functions on servers, network environments, and remote locations. Although these two concepts are similar to some terminologies, such as "Presentation", "service", "business", and "data", we must understand the differences between them. The following figure shows the differences between the multi-layer (n-layer) logical architecture and the three-tier (3-tier) physical structure:
It should be noted that for applications with certain complexityProgramIt is necessary to adopt multi-layer (n-layer) logical architecture, which will reduce the complexity of the system, in addition, it brings positive effects such as high availability and high scalability to the application system in the aspects of design, development, testing, deployment and maintenance. However, not all applications must be deployed in a three-tier/multi-tier (n-tier) physical structure, we can deploy multiple logical layers on the same machine, or deploy these logical layers on different machines on the network as needed.
Design of logical hierarchy
Before discussing the hierarchy of DDD, let's take a look at the traditional hierarchy. As described above, we should rationally divide the component/function module into the "logical layer" based on the actual needs of the project. Components in the same layer should be highly cohesive and have the same abstract hierarchy. Low coupling between layers. For applications with hierarchical design, the most critical issue is how to handle the dependency between layers. Evaluate the knowledge of traditional multi-layer architecture applications. components at a certain layer can only access other components at the same layer or lower layer. This can effectively reduce the dependency between layers. There are usually two types of hierarchy design: strict hierarchy and flexible hierarchy
- Strict layering forces the component to access only other components at the same layer, or only other components at the direct lower layer, so the components at the N layer can only access components at the N or N-1 layer, the components at the N-1 layer can only access the components at the N-1 or N-2 layer, and so on
- Flexible layering allows components to access other components at the same layer, and all other components at the lower layer, so the components at the N layer can access the N or N-1, N-2... Layer components
The "flexible hierarchy" architecture can improve the system performance, because such a structure does not require too many request/feedback transfer operations, because one layer can directly access any layer under it; strict hierarchy reduces the coupling between layers, and changes to the lower layer will not have a wide impact on the entire system. According to Eric Evans's description in his book "Domain-driven design-how to deal with software core complexity", the "flexible hierarchy" mode is selected for DDD.
Let's further refine the granularity of the discussion to see the relationship between components in the layer and components. In fact, in many complex applications, components and components at the same layer have the same abstract level, and they are not necessarily highly cohesive. Therefore, we can introduce the concept of "module" and place the High-cohesion components in the same layer in the same module. Therefore, each layer is composed of one or more highly cohesive subsystems (modules), as shown in the following UML component diagram:
Using a layered architecture has the following benefits:
- Improve System Testability
- It is easier to maintain and manage the solution. The Structure of High Cohesion and low coupling between layers makes the system implementation and hierarchical organization very flexible and convenient.
- Other external applications can easily use the specific functions provided by different layers.
- Distributed development becomes easier and easier when the system is organized in a layer-based manner.
- In some cases, the physical deployment mode of a layered system can extend the system. Of course, it should be effective to evaluate the specific practices, because this approach may damage the system performance.
Basic Design Principles of application systems-Solid
The application system design should follow some basic design principles, which can help you effectively create a low-cost, high-availability, high-scalability application. Here, we introduce a solid design principle, which consists of the following points:
- SIngle Responsibility Principle (single responsibility principle)
- OPen close principle (on-closed principle)
- LIskov substitution principle (RYS replacement principle)
- INterface segregation principle (interface separation principle)
- DEpendency inversion principle (dependency inversion principle)
The following describes the principles ".
- Single Responsibility Principle: each class should have only one unique responsibility, or each class can only have one main function. Thus, a conclusion is drawn: each class should be dependent on other classes as little as possible.
- Open-Close principle: each class should be open to "extension", and "modification" should be closed, that is, extension is supported, rather than modification: methods In the class can be extended through the inheritance relationship, without changing the class'sCode
- Rys replacement principle: subclass can be replaced by the base type (base class or interface. The application depends on abstract running, and its behavior will not be changed because of the specific implementation changes. The application should rely on abstract (base class or interface) instead of specific implementation. The dependency injection that will be discussed next is related to this principle.
- Interface separation principle: the responsibility of an interface should also be single. Which methods should be included in the interface should be strictly evaluated, if the responsibilities of some methods do not conform to the interface definition, they should be separated into other interfaces. Class needs to expose different interfaces according to the different interface types required by its caller
- Dependency inversion principle: Abstraction cannot depend on specifics, but the specifics should depend on abstraction. The direct dependency between classes should be replaced by abstraction. One advantage of this is that we can implement a top-down Design Approach: without the specific implementation of the lower layer, as long as the interface can be determined at the abstract level, the upper-layer design and development can be completed, which also brings convenience to testability.
In addition to the solid principles described above, there are also the following key design principles for your reference:
- The component design should be highly cohesive: I believe everyone is familiar with this, so I won't say much about it. For example, do not write the data access logic into the business logic of the domain model, which is closely related to the aforementioned "single responsibility principle ".
- Separate the cross-cutting code from the application-specific logic: the cross-cutting code is some horizontal code, such as security, operation management, logs, and measurement/measurement systems. Mixing these codes with the application system business logic will increase the complexity of the system and cause great trouble for future expansion and maintenance. This is related to "Aspect-oriented programming (Aspect-Oriented Programming, AOP )".
- Separation of concerns (SOC): the application system is divided into multiple sub-parts (subsystems). The functions of each part should not be repeated as much as possible, so as to reduce interaction points, to achieve high cohesion and low coupling
- Don't repeat yourself (dry): a specific function can only be implemented once in a specific component. Do not repeat the same function multiple times in multiple components.
- Avoid yagni (you ain't gonna need it) effect: only consider and design the necessary functions to avoid over-design
Well, I will introduce it here. It is estimated that for most software friends who have been familiar with the architecture, part of this article is nonsense. At the beginning of the next lecture, I will spend some ink on the layered introduction of DDD/dddd. Although it may be nonsense, it will be quite helpful for us to understand the organization structure of nlayerapp solutions.