Translate the base-practices/module-architecture document

pull/550/head
梁士伟 7 years ago
parent 50a2e55381
commit b61f05ae49

@ -1,3 +1,3 @@
## Domain Services Best Practices & Conventions
## 领域服务最佳实践 & 约定
TODO

@ -1,89 +1,89 @@
## Module Architecture Best Practices & Conventions
## 模块化架构最佳实践 & 约定
### Solution Structure
### 解决方案结构
* **Do** create a separated Visual Studio solution for every module.
* **Do** name the solution as *CompanyName.ModuleName* (for core ABP modules, it's *Volo.Abp.ModuleName*).
* **Do** develop the module as layered, so it has several packages (projects) those are related to each other.
* Every package has its own module definition file and explicitly declares the dependencies for the depended packages/modules.
* **推荐** 在Visual Sudio中为每个模块创建一个单独的解决方案.
* **推荐** 将解决方案命名为*CompanyName.ModuleName*(对于ABP核心模块来说,它的命名方式是*Volo.Abp.ModuleName*).
* **推荐** 一个模块做为分层项目开发,因为它有几个包(项目)是相互关联的.
* 每个包都有自己的模块定义文件,并显式声明所依赖的包/模块的依赖关系.
### Layers & Packages
### 层(layers) & 包(packages)
The following diagram shows the packages of a well-layered module and dependencies of those packages between them:
下面展示了一个分层良好的模块中的包以及它们之间的依赖关系:
![module-layers-and-packages](../images/module-layers-and-packages.jpg)
The ultimate goal is to allow an application to use the module in a flexible manner. Example applications:
* **A)** A **monolithic** application;
* Adds references to the **Web** and the **Application** packages.
* Adds a reference to one of the **EF Core** or the **MongoDB** packages based on the preference.
* The result;
* The application **can show UI** of the module.
* It hosts the **application** and **domain** layers in the **same process** (that's why it needs to have a reference to a database integration package).
* This application also **serves** the module's **HTTP API** (since it includes the HttpApi package through the Web package).
* **B)** An application that just serves the module as a **microservice**;
* Adds a reference to **HttpApi** and **Application** packages.
* Adds a reference to one of the **EF Core** or the **MongoDB** packages based on the preference.
* The result;
* The application **can not show UI** of the module since it does not have a reference to the Web package.
* It hosts the **application** and **domain** layers in the **same process** (that's why it needs to have a reference to a database integration package).
* This application **serves** the module's **HTTP API** (as the main goal of the application).
* **C)** An application that shows the module **UI** but does not host the application (just uses it as a remote service that is hosted by the application A or B);
* Adds a reference to the **Web** and the **HttpApi.Client** packages.
* Configures the remote endpoint for the HttpApi.Client package.
* The result;
* The application **can show UI** of the module.
* It does not host the application and domain layers of the module in the same process. Instead, uses it as a **remote service**.
* This application also **serves** the module's **HTTP API** (since it includes the HttpApi package through the Web package).
* **D)** A **client** application (or microservice) that just uses the module as a remote service (that is hosted by the application A, B or C);
* Adds a reference to the **HttpApi.Client** package.
* Configures the remote endpoint for the HttpApi.Client package.
* The result;
* The application can use all the functionality of the module as a **remote client**.
* The application is just a client and **can not serve** the **HTTP API** of the module.
* The application is just a client and **can not show** the **UI** of the module.
* **E**) A proxy application that hosts the HTTP API of the module but just forwards all requests to another application (that is hosted by the application A, B or C);
* Adds a reference to the **HttpApi** and **HttpApi.Client** packages.
* Configures the remote endpoint for the HttpApi.Client package.
* The result;
* The application can use all the functionality of the module as a **remote client**.
* This application also **serves** the module's **HTTP API**, but actually works just like a proxy by redirecting all requests (for the module) to another remote server.
Next section describes the packages in more details.
#### Domain Layer
* **Do** divide the domain layer into two projects:
* **Domain.Shared** package, named as *CompanyName.ModuleName.Domain.Shared*, that contains constants, enums and other types those can be safely shared with the all layers of the module. This package can also be shared to 3rd-party clients. It can not contain entities, repositories, domain services or any other business objects.
* **Domain** package, named as *CompanyName.ModuleName.Domain*, that contains entities, repository interfaces, domain service interfaces and their implementations and other domain objects.
* Domain package depends on the **Domain.Share** package.
#### Application Layer
* **Do** divide the application layer into two projects:
* **Application.Contracts** package, named as *CompanyName.ModuleName.Application.Contracts*, that contains application service interfaces and related data transfer objects.
* Application contract package depends on the **Domain.Shared** package.
* **Application** package, named as *CompanyName.ModuleName.Application*, that contains application service implementations.
* Application package depends on the **Domain** and the **Application.Contracts** packages.
#### Infrastructure Layer
* **Do** create a separated integration package for each ORM/database integration like Entity Framework Core and MongoDB.
* **Do**, for instance, create a *CompanyName.ModuleName.EntityFrameworkCore* package that abstracts the Entity Framework Core integration. ORM integration packages depend on the **Domain** package.
* **Do not** depend on other layers from the ORM/database integration package.
* **Do** create a separated integration package for each major library that is planned to be replaceable by another library without effecting the other packages.
#### HTTP Layer
* **Do** create an **HTTP API** package, named as *CompanyName.ModuleName.HttpApi*, to develop a REST style HTTP API for the module.
* HTTP API package only depends on the **Application.Contracts** package. It does not depend on the Application package.
* **Do** create a Controller for each application service (generally by implementing their interfaces). These controllers uses the application service interfaces to delegate the actions. It just configures routes, HTTP methods and other web related stuffs if needed.
* **Do** create an **HTTP API Client** package, named as *CompanyName.ModuleName.HttpApi.Client*, to provide client services for the HTTP API package. Those client services implement application interfaces as clients to a remote endpoint.
* HTTP API Client package only depends on the **Application.Contracts** package.
* **Do** use dynamic HTTP C# client proxy feature of the ABP framework.
#### Web Layer
* Do create a **Web** package, named as *CompanyName.ModuleName.Web*, that contains pages, views, scripts, styles, images and other UI components.
* Web package only depends on the **HttpApi** package.
最终的目地是让应用程序以灵活的方式使用该模块. 示例应用程序:
* **A)** **单体**应用程序;
* 添加对**Web**和**Application**包的引用.
* 根据需要添加对**EF Core** 或 **MongoDB** 包的引用.
* 效果;
* 应用程序可以显示**模块的UI**.
* 它在**同一进程**中托管**应用层**和**领域层** (这就是为什么它引用对数据库集成包).
* 此应用程序还提供了模块的**HTTP API**(因为它通过Web包引用了HttpApi包).
* **B)** 仅为**微服务**提供模块的应用程序;
* 添加对**HttpApi**和**Application**包的引用.
* 根据需要添加对**EF Core** 或 **MongoDB** 包的引用.
* 效果;
* 应用程序**无法显示模块的UI**, 因为它没有对Web包的引用.
* 它在**同一进程**中托管**应用层**和**领域层** (这就是为什么它引用对数据库集成包).
* 此应用程序提供了模块的**HTTP API**(它的主要目标).
* **C)** 显示模块**UI**但是不托管应用层的应用程序(仅将其用作由应用程序A或B托管的远程服务)
* 添加对**Web**和**HttpApi.Client**包的引用.
* 配置HttpApi.Client包的远程端点.
* 效果;
* 应用程序可以显示**模块的UI**.
* 它不会在同一进程中托管模块的应用层和领域层. 而是将其用作**远程服务**.
* 此应用程序还提供了模块的**HTTP API**(因为它通过Web包引用了HttpApi包).
* **D)** **客户端**应用程序 (或微服务) 只使用模块作为远程服务(由应用程序A,B或C托管);
* 添加对**HttpApi.Client**包的引用.
* 配置HttpApi.Client包的远程端点.
* 效果;
* 应用程序可以使用模块的所有功能作为**远程客户端**.
* 应用程序只是一个客户端,**无法提供**模块的**HTTP API**.
* 应用程序只是一个客户端,**无法显示**模块的**UI**.
* **E**) 托管模块的HTTP API但只是将所有请求转发给另一个应用程序的代理应用程序 (由应用程序A, B或C托管);
* 添加对**HttpApi**和**HttpApi.Client**包的引用.
* 配置HttpApi.Client包的远程端点.
* 效果;
* 应用程序可以将模块的所有功能用作**远程客户端**.
* 应用程序也服务于模块的**HTTP API**, 但实际上它的工作方式与代理一样,将所有请求(模块)重定向到另一个远程服务器.
下一节将详细地介绍这些包.
#### 领域层
* **推荐** 将领域层划分为两个项目:
* **Domain.Shared** 包(项目) 命名为*CompanyName.ModuleName.Domain.Shared*,包含常量,枚举和其他类型, 它不能包含实体,存储库,域服务或任何其他业务对象. 可以安全地与模块中的所有层使用. 此包也可以与第三方客户端使用.
* **Domain** 包(项目) 命名为*CompanyName.ModuleName.Domain*, 包含实体, 仓储接口,领域服务接口及其实现和其他领域对象.
* Domain package 依赖于 **Domain.Share** package.
#### 应用服务层
* **推荐** 将应用服务层划分为两个项目:
* **Application.Contracts** 包(项目) 命名为*CompanyName.ModuleName.Application.Contracts,包含应用服务接口和相关的数据传输对象(DTO).
* Application contract package 依赖于 **Domain.Shared** package.
* **Application** 包(项目)命名为*CompanyName.ModuleName.Application*,包含应用服务实现.
* Application package 依赖于 **Domain** 和 **Application.Contracts** packages.
#### 基础设施层
* **推荐** 为每个orm/数据库集成创建一个独立的集成包, 比如Entity Framework Core 和 MongoDB.
* **推荐** 例如, 创建一个抽象Entity Framework Core集成的*CompanyName.ModuleName.EntityFrameworkCore* package. ORM 集成 package 依赖于 **Domain** package.
* **不推荐** 依赖于orm/数据库集成包中的其他层.
* **推荐** 为每个主要的库创建一个独立的集成包, 在不影响其他包的情况下可以被另一个库替换.
#### HTTP
* **推荐** 创建命名为*CompanyName.ModuleName.HttpApi*的**HTTP API**包, 为模块开发REST风格的HTTP API.
* HTTP API package 只依赖于 **Application.Contracts** package. 不要依赖 Application package.
* **推荐** 为每个应用服务创建一个Controller (通常通过实现其接口). 这些控制器使用应用服务接口来委托操作. 它根据需要配置路由, HTTP方法和其他与Web相关的东西.
* **推荐** 创建一个为HTTP API包提供客户端服务的**HTTP API Client**包, 它的命名为*companyname.modulename.httpapi*. 这些客户端服务将应用服务接口实现远程端点的客户端.
* HTTP API Client package 仅依赖于 **Application.Contracts** package.
* **推荐** 使用ABP框架提供的动态代理HTTP C客户端的功能.
#### Web
* **推荐** 创建命名为*CompanyName.ModuleName.Web*的 **Web**包. 包含页面,视图,脚本,样式,图像和其他UI组件.
* Web package 仅依赖于 **HttpApi** package.
Loading…
Cancel
Save