适用于 Golang 服务的干净架构模板
模板的目的是显示:
使用罗伯特·马丁(又名鲍勃叔叔)的原则。
Go-clean-template由Evrone创建和支持。
本地发展:
# Postgres, RabbitMQ
$ make compose-up
# Run app with migrations
$ make run
集成测试(可以在 CI 中运行):
# DB, app + migrations, integration tests
$ make compose-up-integration-test
cmd/app/main.go
配置和记录器初始化。然后主函数在 中“继续”。
internal/app/app.go
config
配置。首先,被读取,然后环境变量覆盖 yaml 配置(如果它们匹配)。配置结构位于 .该标记要求你指定一个值(在 yaml 或环境变量中)。
config.yml
config.go
env-required: true
对于配置,我们选择了 cleanenv 库。它在GitHub上没有很多星星,但很简单,满足所有要求。
从 yaml 读取配置与 12 个因素的意识形态相矛盾,但在实践中,它比从 ENV 读取整个配置更方便。假定默认值在 yaml 中,安全敏感变量在 ENV 中定义。
docs
招摇的文档。由赃物库自动生成。你无需自己更正任何内容。
integration-test
集成测试。它们作为应用程序容器旁边的单独容器启动。使用 go-hit 测试 Rest API 很方便。
internal/app
文件中始终有一个 Run 函数,它“继续”主函数。
app.go
这是创建所有主要对象的地方。依赖注入通过“新...”构造函数(请参阅依赖关系注入)。这种技术允许我们使用依赖注入原则对应用程序进行分层。这使得业务逻辑独立于其他层。
接下来,我们启动服务器并等待 select 中的信号以正常完成。如果开始增长,你可以将其拆分为多个文件。
app.go
对于大量注射,可以使用金属丝。
该文件用于数据库自动迁移。如果指定了带有迁移标记的参数,则会包含它。例如:
migrate.go
$ go run -tags migrate ./cmd/app
internal/controller
服务器处理程序层(MVC 控制器)。该模板显示 2 台服务器:
服务器路由器以相同的样式编写:
internal/controller/http
简单的 REST 版本控制。对于 v2,我们需要添加具有相同内容的文件夹。并在文件中添加以下行:
http/v2
internal/app
handler := gin.New()
v1.NewRouter(handler, t)
v2.NewRouter(handler, t)
代替 Gin,你可以使用任何其他 http 框架甚至标准库。
net/http
在处理程序方法中和上方,有使用 swagg 生成 swagger 文档的注释。
v1/router.go
internal/entity
业务逻辑(模型)的实体可以在任何层中使用。还可以有方法,例如,用于验证的方法。
internal/usecase
业务逻辑。
存储库、webapi、rpc 和其他业务逻辑结构被注入到业务逻辑结构中(请参阅依赖关系注入)。
internal/usecase/repo
存储库是业务逻辑使用的抽象存储(数据库)。
internal/usecase/webapi
它是业务逻辑使用的抽象 Web API。例如,它可能是业务逻辑通过 REST API 访问的另一个微服务。包名称根据用途而变化。
pkg/rabbitmq
RabbitMQ RPC 模式:
为了消除业务逻辑对外部包的依赖,使用了依赖注入。
例如,通过 New 构造函数,我们将依赖关系注入到业务逻辑的结构中。这使得业务逻辑独立(且可移植)。我们可以覆盖接口的实现,而无需更改包。
usecase
package usecase
import (
// Nothing!
)
type Repository interface {
Get()
}
type UseCase struct {
repo Repository
}
func New(r Repository) *UseCase{
return &UseCase{
repo: r,
}
}
func (uc *UseCase) Do() {
uc.repo.Get()
}
它还将允许我们自动生成模拟(例如模拟)并轻松编写单元测试。
我们不依赖于特定的实现,以便始终能够将一个组件更改为另一个组件。如果新组件实现了接口,则无需在业务逻辑中进行任何更改。
程序员在编写了大部分代码后,才实现应用程序的最佳体系结构。
一个好的架构允许将决策延迟到尽可能晚的时间。
依赖反转(与 SOLID 相同)是依赖反转的原则。依赖关系的方向从外层到内层。因此,业务逻辑和实体仍然独立于系统的其他部分。
因此,应用程序分为内部和外部两层:
具有业务逻辑的内层应该是干净的。它应该:
业务逻辑对 Postgres 或特定的 Web API 一无所知。业务逻辑具有用于处理抽象数据库或抽象 Web API 的接口。
外层还有其他限制:
internal/entity
例如,你需要从 HTTP(控制器)访问数据库。HTTP和数据库都在外层,这意味着它们彼此一无所知。它们之间的通信通过以下方式(业务逻辑)进行:
usecase
HTTP > usecase usecase > repository (Postgres) usecase < repository (Postgres) HTTP < usecase
符号>和<通过界面显示图层边界的交集。如图所示:
或更复杂的业务逻辑:
HTTP > usecase usecase > repository usecase < repository usecase > webapi usecase < webapi usecase > RPC usecase < RPC usecase > repository usecase < repository HTTP < usecase
实体是业务逻辑操作的结构。它们位于文件夹中。在 MVC 术语中,实体是模型。
internal/entity
用例是位于 中的业务逻辑。
internal/usecase
业务逻辑直接交互的层通常称为基础结构层。这些可以是存储库、外部 webapi、任何 pkg 和其他微服务。在模板中,基础结构包位于 .
internal/usecase/repo
internal/usecase/webapi
internal/usecase
你可以根据需要选择如何调用入口点。选项包括:
清洁体系结构的经典版本专为构建大型整体式应用程序而设计,具有 4 层。
在原始版本中,外层又分为两层,它们之间也有相互依赖的反转(向内定向)并通过接口进行通信。
在复杂逻辑的情况下,内层也分为两层(接口分离)。
复杂工具可以划分为其他图层。但是,仅当确实需要时才应添加图层。
除了清洁架构外,洋葱架构和六边形(端口和适配器)也与之类似。两者都基于依赖反转原则。端口和适配器非常接近干净架构,差异主要在于术语。