在构建 REST api 时,您会选择:
选项 A:
├── controllers |
│ ├── order.go
│ ├── region.go
│ └── user.go
├── models
│ ├── order.go
│ ├── region.go
│ └── user.go
└── repos
├── order.go
├── region.go
└── user.go
选项 B:
├── order |
│ ├── order_controller.go
│ ├── order_entity.go
│ └── order_repo.go
├── region
│ ├── region_controller.go
│ ├── region_entity.go
│ └── region_repo.go
└── user
├── user_controller.go
├── user_entity.go
└── user_repo.go
这是如何在不妥协的情况下在松散耦合和高内聚之间找到平衡。
第一个选项适用于非常小范的项目,其中类型很少,“处理程序”很多,像“ToDo”应用程序,演示,单一职责命令行工具这样的幼稚项目适合这种情况,因为凝聚力不会受到太大影响,因为有每个包中的东西很少。
现第二个适用于其他一切:
如果一旦您在这些目录中拥有大量相同命名的.go文件,那么寻找单一类型的实现和跟踪代码将变得非常笨拙。
两打目录和几个文件比几个文件夹更容易推理,每个文件夹中有两打文件,每个文件夹都命名相同。
这就是为什么我从不选择第一种方法,因为随着熵的增加,它几乎总是蜕变为第二种方法,而且当我可以从那里开始的时候,重新构建所有的东西是浪费时间的。
按团队划分
下面是我们团队的标准布局,我们有一个工具可以保证这一点。
我们的布局是这样的:
├── etc │ └── pet-api.yaml ├── internal │ ├── config │ │ └── config.go │ ├── handler │ │ ├── cat_create_handler.go │ │ ├── dog_create_handler.go │ │ └── routes.go │ ├── logic │ │ ├── cat_create_logic.go │ │ └── dog_create_logic.go │ ├── svc │ │ └── service_context.go │ └── types │ └── types.go └── pet.go |
- etc是yaml配置文件的文件夹
- config包含配置的 Go 定义
- handler包含路由的 HTTP 处理程序
- logic包含每个处理程序的 biz 逻辑
- svc是从外部传入处理程序的服务上下文,例如数据库实例。
- types是定义请求和响应类型的文件夹
为什么我把逻辑文件夹和handler处理程序分开,是因为我希望我们的团队尽可能少地把HTTP请求的信息传递给逻辑处理函数。
另外,所有文件夹的布局是由goctl从下面的API定义文件中生成的,命令是goctl api go -api demo.api -style go_zero -dir .
type ( CatCreateRequest { Name string `path:"name"` } |
CatCreateResponse {
Message string json:</font><font>"message"</font><font>
}
)
type (
DogCreateRequest {
Name string path:</font><font>"name"</font><font>
}
DogCreateResponse {
Message string json:</font><font>"message"</font><font>
}
)
@server(
prefix: v1
)
service pet-api {
@handler CatCreateHandler
post /pets/cats/:name(CatCreateRequest) returns (CatCreateResponse)
@handler DogCreateHandler
post /pets/dogs/:name(DogCreateRequest) returns (DogCreateResponse)
}
前缀:v1将/v1添加到服务中的所有路由,它是可选的。
对于单体服务,我们会在内部下添加模型文件夹,用于数据访问代码。
另外,goctl支持自定义生成行为的选项,比如命名风格、将请求分组到不同的包中,甚至将处理程序和逻辑分别压缩到一个文件中。
安装:go install github.com/zeromicro/go-zero/tools/goctl@latest
六边形架构
对于微型服务来说,拥有如下软件包:
- cmd — service_name — mock_service - internal — entities — errors — repositories —— database —— fxrates_provider — server —— http —— grpc — usecases |
- cmd - 持有启动你的服务的方法
- http/grpc等在/server目录下–你的服务的进入点
- usecases–领域/业务逻辑层
- mysql/firestone/其他一些api在/repositories目录下–来自外部的任何数据
- entities–创建并通过各层传递的模型
- errors–全局错误,使错误检查更容易。
优点。
- 没有循环的依赖关系
- 非常清楚地将逻辑分离出来
- 只要满足预期的接口,就可以互相替换层(你的老板决定明天要支持http? 没问题!)。
- 更容易测试
- 更容易用gomock来模拟接口
- 更容易调试(根据我的经验,更少的面条,更清晰的责任)。
缺点。
- 一些重复的代码
- 转换为实体有时是件麻烦的事